Rename files using regular expression in linux
Edit: found a better way to list the files without using IFS
and ls
while still being sh
compliant.
I would do a shell script for that:
#!/bin/sh
for file in *.srt; do
if [ -e "$file" ]; then
newname=`echo "$file" | sed 's/^.*\([0-9]\+\)x\([0-9]\+\).*$/S0\1E\2.srt/'`
mv "$file" "$newname"
fi
done
Previous script:
#!/bin/sh
IFS='
'
for file in `ls -1 *.srt`; do
newname=`echo "$file" | sed 's/^.*\([0-9]\+\)x\([0-9]\+\).*$/S0\1E\2.srt/'`
mv "$file" "$newname"
done
find + perl + xargs + mv
xargs -n2
makes it possible to print two arguments per line. When combined with Perl's print $_
(to print the $STDIN first), it makes for a powerful renaming tool.
find . -type f | perl -pe 'print $_; s/input/output/' | xargs -d "\n" -n2 mv
Results of perl -pe 'print $_; s/OldName/NewName/' | xargs -n2
end up being:
OldName1.ext NewName1.ext
OldName2.ext NewName2.ext
OldName3.ext NewName3.ext
OldName4.ext NewName4.ext
I did not have Perl's rename
readily available on my system.
How does it work?
find . -type f
outputs file paths (or file names...you control what gets processed by regex here!)-p
prints file paths that were processed by regex,-e
executes inline scriptprint $_
prints the original file name first (independent of-p
)-d "\n"
cuts the input by newline, instead of default space character-n2
prints two elements per linemv
gets the input of the previous line
My preferred approach, albeit more advanced.
Let's say I want to rename all ".txt" files to be ".md" files:
find . -type f -printf '%P\0' | perl -0 -l0 -pe 'print $_; s/(.*)\.txt/$1\.md/' | xargs -0 -n 2 mv
The magic here is that each process in the pipeline supports the null byte (0x00) that is used as a delimiter as opposed to spaces or newlines. The first aforementioned method uses newlines as separators. Note that I tried to easily support find .
without using subprocesses. Be careful here (you might want to check your output of find
before you run in through a regular expression match, or worse, a destructive command like mv
).
How it works (abridged to include only changes from above)
- In
find
:-printf '%P\0'
print only name of files without path followed by null byte. Adjust to your use case-whether matching filenames or entire paths. - In
perl
andxargs
:-0
stdin delimiter is the null byte (rather than space) - In
perl
:-l0
stdout delimiter is the null byte (in octal 000)
You forgot a dot in front of the asterisk:
rename -n 's/(\w+) - (\d{1})x(\d{2}).*$/S0$2E$3\.srt/' *.srt
On OpenSUSE, RedHat, Gentoo you have to use Perl version of rename
. This answer shows how to obtain it. On Arch, the package is called perl-rename
.