8
\$\begingroup\$

This is my homebrew bash script for batch renaming files extensions (my music library needs organizing):

#!/bin/bash

# rext.sh
# Syntax: rext.sh EXT1 EXT2
# Batch rename any file in current directory with extension of EXT1 to EXT2

EXT1=$1
EXT2=$2

for f in *.$EXT1
do
  fname=${f%.*}
  newfname="$fname.$EXT2"
  mv -v -i "$f" "$newfname"
done

It works beautifully with my music files, but is this code sufficient or can I still improve on it? Also I've seen examples using rename instead of mv, so is there any advantage in using rename?

\$\endgroup\$
6
\$\begingroup\$

A tiny mistake is not quoting $EXT1 in for f in *.$EXT1. If it contains a space, the script won't work as expected. I agree it's an unrealistic corner case, but it's easy enough to protect against with proper quoting: for f in *."$EXT1".

The rename Perl script is famous for this purpose. Since you asked about its advantages:

  • Stood the test of time
  • You don't have to write it
  • It has more features (full regex support)

The equivalent usage to simulate the behavior of your script would be:

rename -v 's/EXT1$/EXT2/' *.EXT1

A feature I like is the -n flag for dry run, to verify the renames that would be performed before actually performing them.

\$\endgroup\$
  • 1
    \$\begingroup\$ I agree it would be a corner case, but it's not unlikely to have something like some_file.timestampt\ year, where a newbie would be like "Oh, I can use my shell script to do that". It wouldn't do any harm if there's no files some_file.timestamp and no file year because that's what improper quoting would expand to, but if there are, that would probably rename files to not what user wanted, and they'd come asking where did their files go. Nice answer, by the way \$\endgroup\$ – Sergiy Kolodyazhnyy May 13 '17 at 22:50
5
\$\begingroup\$

Here's a few suggestions:

  • always quote your variables to avoid word splitting as in *."$EXT1"
  • you are using globstar , which suggest that you run your script on files in current working directory. This may break if there is a filename with leading - (which will be understood by mv command as an option flag) , so it's often recommended to use ./* glob instead, and in your specific case you should makeit ./*."$EXT1".
  • typical convention is to use lowercase variables to avoid overwriting environment variables, which are typically upper case; this isn't a written rule, but strongly suggested by professional sysadmins

As for rename command, a few things must be explained. There exist several rename commands. Typically when we talk about rename we are talking about the Perl script, but if you are using Debian or Ubuntu,those have two diverging versions which do the same thing - one comes with Perl installation while the other is standalone package. See this post on Unix & Linux for more info on this topic.

Korn shell and Mir Korn shell have their own, which is why that Perl script is often referenced as prename. The big difference is that Korn shell rename is a built-in and does simple renaming much like mv does. The prename is useful for couple different reasons, but mainly because you can use perl regular expressions to do some really complex renamings. See for example one of my answers on askubuntu. The trick here is that you really want to learn regular expressions first to be able to use rename efficiently and do that complex stuff.

\$\endgroup\$
4
\$\begingroup\$
  • If the script is called without arguments (or maybe with the argument -?) a message how to use the script should be written to stderr.
  • If the script is called with only one or more than 2 arguments an error message should be written to stderr
  • should files be overwritten? Maybe the script should pass its option to the mv command (-i -v -u)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.