I want to rename all the files that match a pattern. This kind of one liners usually work for me, but I'm getting some kind of error.
Kind of file names I have: PMSNpoda5718_1p2g_out_fst.txt SCSNpoda5718_1p2g_out_fst.txt
File names I want: PM-SN_poda5718_1p2g_out_fst.txt SC-SN_poda5718_1p2g_out_fst.txt
My first try was:
ls *fst.txt | perl -ne '/^([A-Z][A-Z])([A-Z][A-Z])(poda.*?$)/; system("mv $_ $1-$2_$3")'
But it didn't work.
Finally I came up with a line that prints exactly what I want
ls *fst.txt | perl -lne '/([a-zA-Z]{2})([a-zA-Z]{2})(poda.*?$)/; print "mv $_ $1-$2_$3"'
prints:
mv PMSNpoda5718_1p2g_out_fst.txt PM-SN_poda5718_1p2g_out_fst.txt
mv SCSNpoda5718_1p2g_out_fst.txt SC-SN_poda5718_1p2g_out_fst.txt
But when I use it in order to rename the files:
ls *fst.txt | perl -lne '/([a-zA-Z]{2})([a-zA-Z]{2})(poda.*?$)/; system("mv $_ $1-$2_$3")'
I get
sh: $'32mPMSNpoda5718_1p2g_out_fst.txt\E[0m': command not found
mv: missing destination file operand after ''$'\033''[01'
Try 'mv --help' for more information.
sh: $'32mSCSNpoda5718_1p2g_out_fst.txt\E[0m': command not found
mv: missing destination file operand after ''$'\033''[01'
Try 'mv --help' for more information.
Again but adding echo
ls *fst.txt | perl -lne '/([a-zA-Z]{2})([a-zA-Z]{2})(poda.*?$)/; system("echo mv $_ $1-$2_$3")'
I get
mv
h: $'32mPMSNpoda5718_1p2g_out_fst.txt\E[0m': command not found
mv
h: $'32mSCSNpoda5718_1p2g_out_fst.txt\E[0m': command not found
Can someone point me which is the error so I can understand what I'm doing wrong?
Thanks!
There is no reason to run the rename via the shell.
ls -1 *fst.txt | perl -MFile::Copy=move -wlnE'
$new = s/([a-zA-Z]{2})([a-zA-Z]{2})/$1-$2_/r; move $_, $new'
Note the -1
option on ls
, so that you do get one filename per line.
The 32m
and [0m
are ANSI escapes, that can set colors (and other properties) for the terminal, often used for shell configuration (for prompt for example). Perhaps your ls
is putting out those and mv
is getting terribly confused with them? One more example of why it's better to avoid going through the shell, unless necessary of course.
In some shells the existing aliasing, whereby a command is in fact run with various options (which is why ls
output gets "dressed" with those codes), can be suppressed by prepending the command by the backslash, \ls
.
Another option is to reduce reliance on the system as much as possible, and build the file list in the program as well
perl -MFile::Copy=move -wE'
for (glob "*fst.txt") {
$new = s/([a-zA-Z]{2})([a-zA-Z]{2})/$1-$2_/r;
move $_, $new or warn "Cant rename $_ to $new: $!" }'
where responsibility for building the correct filelist is now on glob
.