Howto strip/crop and rename multiple file names in a commad line (Linux)

Today was again the day where I needed to rename over 100 file names of an mp3-collection. And again it took me half an hour to make it work. That’s way I decided to write it down now, so I won’t have to think about it again.

The situation is very simple to explain.
My brother-in-law wanted his legally purchased mp3-collection renamed, because he renamed every single song title to something not very smart before. Now some of these mp3s refuses to be inserted into a k3b project list, in order to be recorded onto a DVD-R.
Here goes an example of five song titles:

001 - my first song - Interpreters name [here goes some crap].mp3
002 - my second song - One more Interpreters name [here goes some crap].mp3
003 - my third song - And again one Interpreters name [here goes some crap].mp3
004 - my fourth song - Here's another one [here goes some crap].mp3
005 - my fifth song - Singer [here goes some crap].mp3

Now you just want to have the crap in the song’s title removed. For example the first song:

001 – my first song – Interpreters name [here goes some crap].mp3

should actually look like this:

001 – my first song – Interpreters name.mp3

Well, this can be done in a one-liner, what I also actually did:

IFS=""; for I in $( ls ); do echo $I | awk '{ match($0,"here goes some crap"); print "mv substr($0,1,3)"* "  """substr($0,1,RSTART-5)".mp3""}' ; done > rename.sh

Attention!
This example won’t work for you, unless you’ve adjusted the crap pattern accordingly to your crap. And it won’t work either, if your mp3 doesn’t start with three digits!
I’ve redirected the output into a file, called rename.sh.
You should definitely look into this file and verify its content, afterwards you should make it executable (chmod 755 rename.sh). And please backup your mp3-collection first! (If you read this Blog regularly, you know I don’t make use of exclamation marks often, so please backup your collection first)

One-liner explained:


Internal Field Seperator (IFS)

    If you don’t set this variable, all song titles will we truncated, because after every seperator sign, like a space, tab, or whatever a new line would be assumed.

The loop

    This is really nothing dramatic. A loop in a shell is easy. E.g.

    for I in $(seq 5); do echo $I; done

    The command, that is embraced between the ‘do’ and ‘done’, is executed. And in this example five times.

awk

    awk isn’t that easy anymore, but no rocket science either. We have a

  • match( ) , where we’re looking for the crap in question.
  • The position of the found crap is stored in the special variable RSTART
  • to cut out given pieces of crap from a certain position and for x charaters is done with the substr( ) command
  • finally we print the result with the print command.

You’ ve definitely have to adjust the crap’s name of the example above, and maybe your crap has special characters also. Then you have to put backslashes before them.

In the case above I also avoid to print the full song title name with the crap in it, because the output wouldn’t work with special chars anymore. If you don’t have a leading 3 digit number, you won’t be able to move e.g. “001*” to “001 - song.mp3” anymore, and the script would look a bit more complicated. In such cases you should be good at shell scripting or use a more sophisticated tool for it.

Btw. If you’ve got such an absolutely unbearable crap in your name, where you even don’t have such keys on your keyboard, and cut&paste doesn’t work either, consider using inodes. The find command calls it ‘inum‘. So if you for example like to delete really evil crap from your hdd, you can always list your directories content with ls -li. Here is a little sequence, which shows you how a file is created first, listed, and deleted again, without having used its name:

#touch crap
#ls -li
483592 -rw-r--r-- 1 acme acme 0 2009-01-11 23:41 crap
#find . -inum 483592 -exec rm {} ;

5 thoughts on “Howto strip/crop and rename multiple file names in a commad line (Linux)

  1. There’s probably a few hundred if not thousands of Linux rename scripts/tips out there.

    Personally, I’m using something I picked out of a Perl book examples a long time ago, and called it “rename” not surprisingly. It does require you’re familiar with (perl) regular expressions; if you’re not, then this is probably not for you.

    Your example would be done like this:

    rename ‘s/[.*]//’ *.mp3

    (with s/ … / … / being the substitute operation).

    Here’s the perl code:

    #!/usr/bin/perl

    # Usage: rename perlexpr [files]

    ($op = shift) || die "Usage: rename perlexpr [filenames]n";
    if (!@ARGV) {
    @ARGV = ;
    chop(@ARGV);
    }
    $filenum = 0;
    for (@ARGV) {
    $filenum++;
    $was = $_;
    eval $op;
    die $@ if $@;
    rename($was,$_) unless $was eq $_;
    }

  2. Oops, looks like the HTML ate part of the code.

    Line 7 be like this (I hope this works now):

    @ARGV = <STDIN>;

  3. @Wizzu
    Really cool!
    Another question I’ve been asking myself for ages now is, how to do this DOS example in a bash shell:

    move *.avi *.mpg

    The bash solution for me atm is still:

    for I in $(ls *.avi)
    do
    WITHOUTH_AVI=$(echo $I | tr -d ".avi$")
    mv $I "$WITHOUT_AVI".mpg;
    done

    and in this example must not be SPACES in the filename.

    Does anybody have another soltion?

  4. Well, my rename script can do that with the s/// expression easily (‘s/.avi$/.mpg/’) but if that’s not what you want, then I suppose your shell commands work fine.

    I should point you there’s a “basename” command which gives you the file’s name without the extension, so no need to do echo/tr trickery.
    One web page I just googled shows it as:

    for old in *.avi; do mv “$old” “`basename $old .avi`.mpg”; done

    You can work also with filenames containing spaces if you put double quotes in proper places (I added them in the above).

  5. @Wizzu
    Cool!
    The ‘s///’ trick is cool, and I’ve discovered it for me also. Actually I wrote a little article about it immediately, because I was so excited 😉 See here.

    But your for; do ... ;done line was a quite a surprise, because I didn’t know the ‘basename NAME [SUFFIX]‘ trick. This is really cool, and is much cleaner this way!

    Thanks a lot!

Comments are closed.