How to batch rename files using bash
2014-07
I know there are lots of such questions, but I couldn't find one (or a combination of several), which describes the things I want to do. I think I need to use regular expressions, but I am not very good with that. I use zsh. I have a folder with files, which I want to rename:
I want the files
challenge1.rb
,challenge2.rb
,challenge3.rb
, etc. to be renamed toc1.rb
,c2.rb
etc. Similarlytask1.rb
and similar must be renamed tot1.rb
etc.sample_spec_c1.rb
,sample_spec_c2.rb
etc. must be renamed toc1_spec.rb
,c2_spec.rb
etc.
So I guess I need some combination of regular expressions and iteration, but I don't know how to write the bash script.
Here is a short script which will do what you want. You can call the script with a list of files like: ./scriptname *.rb
or with directories (it will recurse them): ./scriptname .
Do not forget to set the executable bit: chmod a+x scriptname
.
#!/bin/sh
suff=rb # suffix of files to rename
script="$0" # this script name for recursion
for f in "$@" ; do
if test -d "$f" ; then
echo "=== recursing directory $f"
find "$f" -type f -name "*.$suff" -exec "$script" {} +
elif test -f "$f" ; then
d="$(dirname "$f")"
b="$(basename "$f")"
r="$(echo "$b" | sed -r "s/^([a-zA-Z])[a-zA-Z]*([0-9]+\.${suff})\$/\1\2/;s/^[a-zA-Z]+_([a-zA-Z]+)_([a-zA-Z]+[0-9]+)(\.${suff})\$/\2_\1\3/")"
echo "-- renaming $f -> $d/$r"
mv "$f" "$d/$r"
fi
done
I've got some files like this:
database1-backup-01-01-2011.sql
database2-backup-01-01-2011.sql
...etc. I want to rename them to add AM, like this:
database1-backup-01-01-2011-AM.sql
database2-backup-01-01-2011-AM.sql
What's the most concise way to do that from the bash shell?
Another option:
for i in *.sql ; do
mv -v $i ${i%.sql}-AM.sql
done
This loops through all the .sql files and renames them to end in -AM.sql instead.
PROTIP: Use $(command)
instead of `command`
in your scripts (and command-lines), it makes quoting and escaping less of a nightmare.
Try this little script:
#!/bin/sh
FILES=`ls *.sql`
for FILE in ${FILES}
{
BASE=`basename ${FILE} .sql`
mv ${FILE} ${BASE}-AM.sql
}
I just typed that from memory so if it doesn't work 100% don't blame me (i.e., back up your data first ;) )
How it works:
Collect all files into a variable (you could put this inside the for instead but I like to keep things easy to read):
FILES=`ls *.sql`
Loop through each file:
for FILE in ${FILES} { ... }
Get the filename without .sql:
BASE=`basename ${FILE} .sql`
Rename the file, adding -AM.sql to the base name:
mv ${FILE} ${BASE}-AM.sql
Using the Perl script version of rename
:
rename 's/\.sql$/-AM$&/' *.sql
Using the util-linux-ng
version of rename
(but only if ".sql" only appears at the end of the filename):
rename .sql -AM.sql *.sql
Using mmv
:
mmv '*.sql' '#1-AM.sql'
Since a Perl script has been suggested, here's a Ruby script to do the same:
`ls *.sql`.split("\n").each do |filename|
new_filename = filename.split('.').join('-AM.')
`mv #{filename} #{new_filename}`
end