Renaming files with perl - perl

I'm very new to perl, and I want to rename a group of files so that they are lowercase instead of uppercase (so from SBC005.wav -> sbc005.wav).
use strict;
use warnings;
my $dirnam = "/Users/.../SoundFiles";
opendir(DIR, $dirnam) or die "Cannot open directory: $!";
my #files = readdir(DIR);
foreach my $oldfile (#files) {
my $newfile = lc($oldfile);
#print $newfile;
#print $oldfile;
rename $oldfile, $newfile or die "Cannot rename file: $!";
}
closedir(DIR);
I checked that the variables are working right with the commented out print statements, but when I run the program I get a message that says "Cannot rename file: Invalid argument at rename.pl line 13." I'm not sure what I'm doing wrong here.
Thank you so much!
edit:
Thank you so much to the answer below! I found that this code using glob works too, but the code below works better because it does not have to be in the same directory as the sound files (as the glob code does)
use strict;
use warnings;
my #files = glob("*.wav");
foreach my $oldfile (#files) {
my $newfile = lc($oldfile);
#print $newfile;
#print $oldfile;
rename $oldfile, $newfile or die "Cannot rename file: $!";
}
exit 0;

Try this. you forgot to add the path of directory while renaming.
use strict;
use warnings;
my $dirnam = "/Users/.../SoundFiles";
opendir(DIR, $dirnam) or die "Cannot open directory: $!";
my #files = readdir(DIR);
foreach my $oldfile (#files)
{
unless($oldfile eq "." || $oldfile eq ".." )
{
my $newfile = lc($oldfile);
rename "$dirnam/$oldfile", "$dirnam/$newfile" or die "Cannot rename file: $!";
}
}

Related

To parse multiple files in Perl

Please correct my code, I cannot seem to open my file to parse.
The error is this line open(my $fh, $file) or die "Cannot open file, $!";
Cannot open file, No such file or directory at ./sample.pl line 28.
use strict;
my $dir = $ARGV[0];
my $dp_dpd = $ENV{'DP_DPD'};
my $log_dir = $ENV{'DP_LOG'};
my $xmlFlag = 0;
my #fileList = "";
my #not_proc_dir = `find $dp_dpd -type d -name "NotProcessed"`;
#print "#not_proc_dir\n";
foreach my $dir (#not_proc_dir) {
chomp ($dir);
#print "$dir\n";
opendir (DIR, $dir) or die "Couldn't open directory, $!";
while ( my $file = readdir DIR) {
next if $file =~ /^\.\.?$/;
next if (-d $file);
# print "$file\n";
next if $file eq "." or $file eq "..";
if ($file =~ /.xml$/ig) {
$xmlFlag = 1;
print "$file\n";
open(my $fh, $file) or die "Cannot open file, $!";
#fileList = <$fh>;
close $file;
}
}
closedir DIR;
}
Quoting readdir's documentation:
If you're planning to filetest the return values out of a readdir, you'd better prepend the directory in question. Otherwise, because we didn't chdir there, it would have been testing the wrong file.
Your open(my $fh, $file) should therefore be open my $fh, '<', "$dir/$file" (note how I also added '<' as well: you should always use 3-argument open).
Your next if (-d $file); is also wrong and should be next if -d "$dir/$file";
Some additional remarks on your code:
always add use warnings to your script (in addition to use strict, which you already have)
use lexical file/directory handle rather than global ones. That is, do opendir my $DH, $dir, rather than opendir DH, $dir.
properly indent your code (if ($file =~ /.xml$/ig) { is one level too deep; it makes it harder to read you code)
next if $file =~ /^\.\.?$/; and next if $file eq "." or $file eq ".."; are redundant (even though not technically equivalent); I'd suggest using only the latter.
the variable $dir defined in my $dir = $ARGV[0]; is never used.

Perl script returning 0 when a file is read

Im just trying to copy a file to a different directory before I process it. Here is the code:
use File::stat;
use File::Copy;
use LWP::UserAgent;
use strict;
use warnings;
use Data::Dumper;
use Cwd qw(getcwd);
my $dir = "\\folder\\music";
my $dir1 = "c:\\temp";
opendir(my $dh, $dir) or die "Cant open directory : $!\n";
#my #list = readdir($dh)
my #files = map { [ stat "$dir/$_", $_ ] }
grep( /Shakira.*.mp3$/, readdir( $dh ) );
closedir($dh);
sub rev_by_date
{
$b->[0]->ctime <=> $a->[0]->ctime
}
my #sorted_files = sort rev_by_date #files;
my #newest = #{$sorted_files[0]};
my $name = pop(#newest);
print "Name: $name\n";
#**********************
#Upto here is working fine
my $new;
open OLD,"<",$name or die "cannot open $old: $!";
from here the problem starts
open(NEW, "> $new") or die "can't open $new: $!";
while ()
{
print NEW $_ or die "can't write $new: $!";
}
close(OLD) or die "can't close $old: $!";
close(NEW) or die "can't close $new: $!";
The error im getting is :
cannot open Shakira - Try Everything (Official Video).mp3: No such file or directory at copy.pl line 49.
when Im chomping the filename, like
my $oldfile = chomp($name);
then the error is :
Name: Shakira - Try Everything (Official Video).mp3
old file is 0
cannot open 0: No such file or directory at copy.pl line 49.
Any idea?
chomp changes its argument in place and returns the number of removed characters. So the correct usage is
chomp(my $oldfile = $name);
Also, you probably wanted
while (<OLD>) {
instead of
while () {
which just loops infinitely.
Moreover, you correctly prepend $dir/ to a filename in the stat call, but you shold do so everywhere.

Perl - search and replace across multiple lines across multiple files in specified directory

At the moment this code replaces all occurences of my matching string with my replacement string, but only for the file I specify on the command line. Is there a way to change this so that all .txt files for example, in the same directory (the directory I specify) are processed without having to run this 100s of times on individual files?
#!/usr/bin/perl
use warnings;
my $filename = $ARGV[0];
open(INFILE, "<", $filename) or die "Cannot open $ARGV[0]";
my(#fcont) = <INFILE>;
close INFILE;
open(FOUT,">$filename") || die("Cannot Open File");
foreach $line (#fcont) {
$line =~ s/\<br\/\>\n([[:space:]][[:space:]][[:space:]][[:space:]][A-Z])/\n$1/gm;
print FOUT $line;
}
close INFILE;
I have also tried this:
perl -p0007i -e 's/\<br\/\>\n([[:space:]][[:space:]][[:space:]][[:space:]][A-Z])/\n$1/m' *.txt
But have noticed that is only changes the first occurence of the matched pattern and ignores all the rest in the file.
I also have tried this, but it doesn't work in the sense that it just creates a blank file:
use v5.14;
use strict;
use warnings;
use DBI;
my $source_dir = "C:/Testing2";
# Store the handle in a variable.
opendir my $dirh, $source_dir or die "Unable to open directory: $!";
my #files = grep /\.txt$/i, readdir $dirh;
closedir $dirh;
# Stop script if there aren't any files in the list
die "No files found in $source_dir" unless #files;
foreach my $file (#files) {
say "Processing $source_dir/$file";
open my $in, '<', "$source_dir/$file" or die "Unable to open $source_dir/$file: $!\n";
open(FOUT,">$source_dir/$file") || die("Cannot Open File");
foreach my $line (#files) {
$line =~ s/\<br\/\>\n([[:space:]][[:space:]][[:space:]][[:space:]][A-Z])/\n$1/gm;
print FOUT $line;
}
close $in;
}
say "Status: Processing of complete";
Just wondering what am I missing from my code above? Thanks.
You could try the following:
opendir(DIR,"your_directory");
my #all_files = readdir(DIR);
closedir(DIR);
for (#all_files) .....

Rename and number files in a directory

I'm trying to rename all tif files in a folder and number them from 1 to x. Ex. initial filenames "image-2.tif" and "image-3.tif" would be rename "file1.tif" and "file2.tif".
Here is my code:
my $dirname = "../folder";
opendir (DIR, $dirname) or die "cannot open directory $dirname";
my #files = grep /.tif/, readdir DIR;
closedir (DIR);
my $basename = "file";
my $count = 1;
my $new;
foreach (#files) {
$new = "${basename}${count}.tif";
print "rename $_ ${basename}${count}.tif\n";
rename $_, $new;
$count++;
}
Although all files are read correctly, they are just not renamed.
You need to use a good path for your rename() function when you get the files from a different one. The module File::Spec can help to get it:
use File::Spec;
my $dirname = "../folder";
my $abs_path = File::Spec->rel2abs($dirname);
And:
foreach (#files) {
$new = "${basename}${count}.tif";
print "rename $_ ${basename}${count}.tif\n";
rename File::Spec->catfile($abs_path, $_), File::Spec->catfile($abs_path, $new);
$count++;
}
I would suggest changing your line:
rename $_, $new;
...to something more like:
rename($_, $new) or warn "rename: $_: $new: $!\n";
...and you should be able to see why it isn't working -- since rename returns false upon failure (and $! will tell you why it failed).
Also, the target of your rename operation (in your case: $new) needs to include the directory component as well (otherwise, your attempting to move the files into the process's current working directory (probably not what you intended)).
Finally, I would suggest that, instead of hard-coding the value of $dirname to a relative path, you should accept it as a command line argument. This allows your script to be run from any $PWD. See #ARGV in the perlvar manpage and/or the builtin shift command.
Therefore, something like this:
my $dirname = shift; # Accept dirname as commandline argument
opendir (DIR, $dirname) or die "cannot open directory $dirname";
my #files = grep /\.tif$/, readdir DIR; # Escape regex meta-char (.) and anchor to end of string ($).
closedir (DIR);
my $basename = "file";
my $count = 1;
my $new;
foreach (#files) {
$new = "${dirname}/${basename}${count}.tif"; # Include dirname in target path
print "rename $_ $new\n";
rename($_, $new) or warn "rename: $_: $new: $!\n"; #warn when rename fails
$count++;
}
I finally found exactly what I was looking for. With the help of Tim Peoples's response. The simplest response would be:
my $dirname = "../folder";
opendir (DIR, $dirname) or die "cannot open directory $dirname";
my #files = grep /[.]tif\z/, readdir DIR; #corrected pattern based on Sinan Ünür's comment
closedir (DIR);
my $basename = "file";
my $count = 1;
my $new;
foreach (#files) {
$new = "${basename}${count}.tif";
print "rename $_ $new\n";
rename ("$dirname/$_", "$dirname/$new") or warn "rename: $_: $new: $!\n"; #directory name added to both the original file name and new file name. Thanks to Tim for helping me found this error using warn.
$count++;
}

Find a specific word in a file

First, I want to search for a particular file in the directory and then in the file I need to search for a specific word. Here's what I have so far:
$show_bp = 'ShowBuildProcess';
$get_bs = 'GetBuildStatus';
opendir (DIR, $my_dir) or die $!;
while(my $file = readdir(DIR))
{
if($file=~/\.log/)
{
if($file=~/GetBuildStatus/)
{
Filenames will be like GetStatus.<number>.log, e.g. GetStatus.123456.log. I need to:
Find all .log files in the directory
Search for a file with filename starting with GetStatus
Search for filename with the lower numeric part
Search for a particular word in that file
Here is a possible solution for you:
First we look at the file pattern and also extract $1,which is the first regex match )in the brackets). If the file fits we open it and look through it line by line and look for a match to your /YourSearchPattern/:
#!/usr/bin/perl
use warnings;
use strict;
my $mydir = './test/';
opendir (DIR, $mydir) or die $!;
while(my $file = readdir(DIR)){
if ($file =~ /^GetStatus\.(\d+)\.log$/){
if ($1 >= 123456 || $1 < 345678){
open(my $fh,'<', $mydir . $file) or die "Cannot open file $file: $!\n";
while (<$fh>){
if ($_ =~ /YourSearchPattern/){
print $_;
}
}
close($fh);
}
}
}
When you look for the smallest sequence number of the files from your dir you can simply store them in an array and then sort them after those numbers:
...
opendir (DIR, $mydir) or die $!;
my #files;
while(my $file = readdir(DIR)){
if ($file =~ /^GetStatus\.(\d+)\.log$/){
push #files $file;
}
}
my #sortedfiles = sort { my ($anum,$bnum); $a =~ /^GetStatus\.(\d+)\.log$/; $anum = $1; $b =~ /^GetStatus\.(\d+)\.log$/; $bnum = $1; $anum <=> $bnum } #files;
print $sortedfiles[0] . " has the smallest sequence number!\n";