After Hours

How to automatically rename and reorder MP3 files

If you need to impose some order on your collection of music or other audio files, Marco Fioretti shares a script that uses ID3 tags to rename your files in a uniform system.
Having a huge audio collection doesn't mean anything if you can't always find just the song or podcast you want in that moment. The roughest, but also by far the most future-proof and portable way to handle this problem, is to name all your audio files, and the folders they are in, according to one, coherent naming scheme. Here, I explain a general method to accomplish this task automatically, by means of ID3 tags.

What are ID3 tags anyway?

Here's the definition, straight from ID3.org: ID3 is an audio file data tagging format. An ID3 tag is a data container within an MP3 audio file, stored in a prescribed format. These tags are already supported by all the MP3 players for Linux. You could also use those programs to rename your files. Here, however, we'll see how to do it without even opening any of those tools, and you can even do it remotely. I reordered my uncle's completely messed up music collection without leaving my home, by running the script below via SSH!

Here's the script

    1  #! /bin/bash
    2
    3  declare -A id3tags
    4  id3tags[TITLE]="TIT2|TT2"
    5  id3tags[ALBUM]="TALB|TAL"
    6  id3tags[YEAR]="TYER"
    7  id3tags[LEAD]="TPE1|TPE2"
    8
    9  for SONG in `find $1 -type f -name "*mp3"`
   10  do
   11    rm -f /tmp/song_tags /tmp/song_info
   12    id3info $SONG > /tmp/song_info
   13    VALUE=''
   14    COMPLETE="Y"
   15    for TAG in "${!id3tags[@]}"
   16      do
   17        COMMAND="VALUE=${BACKQUOTE}egrep '${id3tags[$TAG]}' /tmp/song_info | head -1 | cut -d: -f2- ${BACKQUOTE}"
   18        eval $COMMAND
   19        if [ -z "$VALUE" ]
   20         then COMPLETE="N"
   21        else
   22           echo -n "$TAG=" >> /tmp/song_tags
   23           echo $VALUE | perl -n -e 's/\W/_/g; s/^_+//; s/_+$//; s/_+/_/g; print "$_\n"' >> /tmp/song_tags
   24        fi
   25      done
   26    if [ "$COMPLETE" == "Y" ]
   27      then
   28      echo "##################################################################################"
   29      echo "# Moving or renaming FILE: $SONG"
   30      source /tmp/song_tags
   31      # YOUR COMMAND HERE!!!
   33     fi
   34  done
   35  exit

For me, title, performer, year and album name of a song are enough to classify and rename it, but everybody is different. That's no problem! If you want to analyze more tags with this script, just add the corresponding elements to id3tags (lines 3-7).

What is id3tags, you ask? Well, it's an associative array -- that is, a data structure whose elements are addressed via keys instead of numeric indexes: the key "YEAR", for example, identifies the id3tags element whose value is "TYER". Listing the tags to look at with an associative array makes it possible to add as many tags you want without changing the core part of the script.

How does the script work?

id3info is a command line utility, available as binary package for all the most common Linux distributions, that prints out all the ID3 tags it finds in a given file. The script runs id3info on all the files with mp3 extension in the directory passed as first argument (line 9), saving its output in /tmp/song_info (line 12).

The loop in lines 15 to 25 extracts from /tmp/song_info all and only the tags defined in the id3tags array. In order to do so (cfr lines 17-18), we first build on the fly the command to assign a tag's content to $VALUE and then evaluate it. More or less, this is equivalent to running $COMMAND as if it had been written in the script from the start.

Should a tag be undefined, its length will be zero (line 19), so we'll declare the information to be NOT complete. Otherwise, we'll add a variable assignment command to /tmp/song_tags. To give you an idea of what I'm talking about, if running id3tags on unknown_music.mp3 produced this result (only excerpt is shown):
  *** Tag information for unknown_music.mp3
  === TIT2 (Title/songname/content description): For A Few Dollars More(1)
  === TYER (Year): 1990
  === TALB (Album/Movie/Show title): The Legendary Italian Westerns
  === TPE1 (Lead performer(s)/Soloist(s)): Ennio Morricone
then the script would write these lines into /tmp/song_tags:
  TITLE=For_A_Few_Dollars_More_1
  ALBUM=The_Legendary_Italian_Westerns
  LEAD=Ennio_Morricone
  YEAR=1990

(Note that all the non alphabetical characters were replaced by underscores by the Perl invocation of line 23)

If $COMPLETE is still "YES" after the loop, that is, if all the tags are present, we source /tmp/song_tags (line 30), to load their values inside $TITLE, $ALBUM, $LEAD and $YEAR. Which, in case you were wondering, was the main point of the script. Once we have those variables properly loaded, we can, in fact, easily build commands that rename and/or rearrange MP3 files according to whatever criteria we like best. You want your songs all inside /music/, with names as LEAD_ALBUM_TITLE_YEAR.mp3? OK: replace line 30 with:

mv $SONG /music/${LEAD}_${ALBUM}_${TITLE}_${YEAR}.mp3

You prefer nested folders? No problem! Just write in line 30 something like this:

mv $SONG /music/$LEAD/$YEAR/$ALBUM/$TITLE.mp3

Other uses (and limits) of this script

To know how many tags (that is, how many different criteria for processing) you already have inside your MP3 files, run this command, replacing COLLECTION with the absolute path to the folder where you keep them:

find COLLECTION -type f -exec id3info {} \; | grep === | cut -d: -f1 | sort | uniq

You'll quickly see that you may use the script above as a starting point to create playlists, archives and, why not, musical culture tests, ordered by license, duration, language, popularity, label and much more.

Of course, the script won't accomplish anything if there are no ID3 tags to work on. Could we add them to all our songs and podcasts, in the fastest possible way? Of course! Come back next week to know how!

About

Marco Fioretti is a freelance writer and teacher whose work focuses on the impact of open digital technologies on education, ethics, civil rights, and environmental issues.

3 comments
Cabji
Cabji

Hi Marco,


I have expanded on your script, allowing configuration for converting case of values from ID3 to lower case, title or the same as Id3 value. Also it can be configured to add leading zeros track numbers if they are used.


I have not finished with the script yet, as some unexpected results occur from some values in the track number ID3 tag, but is it ok for me to publish modified script on my website, including credit to you as the original author?


still_dvs
still_dvs

During my first tests of this script, lines 17-18 through errors, resulting in an empty VALUE variable. First modification was to place a space (ASCII 32) before "egrep" in line 17 - this allowed /tmp/song_info to be filled, but still didn't assign text to VALUE. To get proper functioning, I had to substitute these lines for 17&18 COMMAND="egrep '${id3tags[$TAG]}' /tmp/song_info | head -1 | cut -d: -f2- " VALUE=$(eval $COMMAND)

mfioretti
mfioretti

probably I messed something up when copying the script from its own file to the text of the article, sorry

Editor's Picks