You aren't executing anything. When you put something in single quotes (''
), that's just a string, so 'mv "$file" "$var1"'
is not a command, it's a string and doesn't do anything. A string by itself is just a true statement. In order to execute the command, you need to use:
system "mv", "--", $file, $var1;
(Not system("mv '$file' '$var1'")
which would introduce a command injection vulnerability).
But there's no need for that, perl
has a rename()
function, so you can do:
rename($file, $var1)
Next, you really shouldn't parse the output of ls
, that is a very bad idea and fragile. It is also completely unnecessary in Perl (or any other programming language). If you want to match all files in the current directory containing the string pre_
(which is what your grep
does—you don't need the grep
, by the way, you could have just used ls -d -- *pre_*
), you can use glob()
like this:
my @files = glob("*pre_*");
So, putting all that together, this is what you were trying to do:
#!/usr/bin/perl -w
use File::Glob qw(:globally :nocase);
my @files = glob("*pre_*");
foreach $file ( @files )
{
my @names = split(/pre_/i, $file);
rename($file, $names[1]);
}
But this isn't really a good idea. If you have two files with the same prefix (e.g. pre_file1
and apre_file1
), then the first file will be overwritten by the second file since, in this example, both files would be renamed to file1
because your command would remove pre_
and everything before it. So you can add a warning and skip those files:
#!/usr/bin/perl -w
use File::Glob qw(:globally :nocase);
my @files = glob("*pre_*");
foreach $file ( @files )
{
my @names = split(/pre_/i, $file);
if (-e $names[1]) {
warn "Warning: Not renaming '$file' to '$names[1]' " .
"because '$names[1]' exists.\n";
next;
}
rename($file, $names[1]) or
warn "rename '$file': $!\n";
}
Of course, all of this is reinventing the wheel. You can just install perl-rename
(on Debian, Ubuntu, etc. run apt install rename
, on other systems it might be called prename
or perl-rename
), and then you can do (although this is not case insensitive, it only finds files containing pre_
):
rename -n 's/.*?pre_//si' ./*
The -n
causes rename
to just print what it would do, without actually renaming. Once you are sure the renaming works as expected, run the command again without the -n
to actually rename the files.
Here the shell passes all (non-hidden) files to rename
and rename
will ignore the files whose name the perl
code doesn't change. You could also tell the shell to only pass the file names that contain pre_
case-insensitively with ./~(i)*pre_*
in ksh93
, ./(#i)*pre_*
in zsh -o extendedglob
, setting the nocaseglob
option globally in bash
, zsh
or yash
or use ./*[pP][rR][eE]_*
.
mv
. My suspicion is that the grep pattern is wrong and returns no file names (maybe the backslashes are not wanted), but I don't do Perl. Or maybe the mv statement needs a keyword to actually execute it.mv
line?pre_
in their name? Why-i
forgrep
, but noi
flag in/pre_/
. Do you or do you not want the match to be case insensitive?