I am trying to rename a bunch of songs using metaflac (sudo apt-get install flac) from their respective tags recursively, because I'm dealing with an unknown number of subfolders.

Output should be: $TRACKNUMBER. $TITLE.flac

This is my attempt, however it does not work recursively:

for a in *.flac; do
TITLE=`metaflac "$a" --show-tag=TITLE | sed s/.*=//g`
TRACKNUMBER=`metaflac "$a" --show-tag=TRACKNUMBER | sed s/.*=//g`
mv "$a" "`printf %02g $TRACKNUMBER`. $TITLE.flac";

I do not know why, but sometimes I get "The FLAC file could not be opened. Most likely the file does not exist or is not readable. *.flac: ERROR: reading metadata, status = "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE"".

Is there a better way to do it in a recursive manner? I also prefer oneliners. Thanks in advance!

  • I got this error only in file names that contained spaces – Amir Uval Jul 10 '16 at 9:06

If you put your code into its own file, make it executable, and place in your binary path (e.g. ~/bin).

e.g. rename_flac_tracks_from_meta.sh

You could then use find and xargs to recursively go through your directories and apply your script to each one.

$ cd path/to/flac/folders
$ find . -type d -print0 | xargs -0 -t -I{} sh -c 'cd "{}"  && rename_flac_tracks_from_meta.sh'

Bear in mind that will crawl into directories that might not have flacs in, but it should just hiccup rather than die.


I have found a python script written by Louis-Philippe Véronneau.

The up to date code can be found on his git repository: https://gitlab.com/baldurmen/rename-flac

You need to install python-docopt (sudo apt-get install python-docopt) and run this script after you chmod +x rename-flac.py it:


rename-flac takes the information from FLAC metadata to batch rename
the files according to a filenaming scheme.

    rename-flac.py [--verbose] <scheme> <directory>
    rename-flac.py (-h | --help)
    rename-flac.py --version

    <scheme>         The filenaming scheme. Has to be between quotation marks
    <directory>      The path to the directory containing the album

    -h  --help       Shows the help screen
    --version        Outputs version information
    --verbose        Runs the program as verbose mode

    These are the options you can use to define the filenaming scheme:
      %a = Artist  |   %b = Album         |   %d = Date
      %g = Genre   |   %n = Tracknumber   |   %t = Title
import sys

    from docopt import docopt  # Creating command-line interface
except ImportError:
        %s is not installed: this program won't run correctly.
        To install %s, run: aptitude install %s
        """ % ("python-docopt", "python-docopt", "python-docopt"))

import subprocess
import re
import os

TAGS = dict(a='artist', b='album', d='date',
            g='genre', n='tracknumber', t='title')

# Defining the function that fetches metadata and formats it
def metadata(filepath): 
    args = ["--show-tag=%s" % tag for tag in TAGS.values()]
    tags = ["%s=" % tag for tag in TAGS.values()]
    formatter = dict()
    pipe = subprocess.Popen(["metaflac"] + args + [filepath],
    output, error = pipe.communicate()
    if pipe.returncode:
        raise IOError("metaflac failed: %s" % error)
    output = output.splitlines()
    for tag in tags:
        for item in output:
            x = re.compile(re.escape(tag), re.IGNORECASE)
            if bool(re.match(x, item)) ==  True:
                tag = tag.replace("=", "")
                if tag == "tracknumber":
                    formatter[tag] = x.sub("", item).zfill(2)
                    formatter[tag] = x.sub("", item)
    return formatter

# Defining function that renames the files
def rename(scheme, dirname, filename, args):
    filepath = os.path.join(dirname, filename)
    new_filename = scheme % metadata(filepath) + ".flac"
    if new_filename == filename:
        if args["--verbose"] == True:
            print("%s is already named correctly") % (filename)
        new_filepath = os.path.join(dirname, new_filename)
        os.rename(filepath, new_filepath)
        if args["--verbose"] == True:
            print("%s >> %s") % (filename, new_filename)

# Defining main function
def main():
    args = docopt(__doc__, version="rename-flac 1.0")
    scheme = args["<scheme>"]
    if not re.search("%[tn]", scheme):  # To have a unique filename
        sys.stderr.write("%t or %n has to be present in <scheme>\n")
    scheme = re.sub('%%([%s])' % ''.join(TAGS.keys()),
                lambda m: '%%(%s)s' % TAGS[m.group(1)],
    for dirname, _, filenames in os.walk(
        for filename in filenames:
            if os.path.splitext(filename)[1] == ".flac":
                    rename(scheme, dirname, filename, args)
                except KeyboardInterrupt:
                except OSError:
                    print("Song title contains /. Please rename it")

# Calling main function
if __name__ == "__main__":

I tested it and everything works like a charm! Thank you!


I've encountered a GUI software called easyTAG that can rename files according to their metadata tags.

The trick is to open the 'scanner' in easyTAG and change the 'scanner-mode' to 'renaming files'.


An alternative to writing your own recipe using metaflac is to use a tagging tool.

I use the Ex Falso GUI to fetch and edit tags and rename files.


I do a lot of my tag management piecemeal and it's all a little laborious.

I discovered Beets sadly after I'd done a lot of grunt work. It can automate many tasks. Beets can be used to help you organise your media files. It will fetch and write tags, help with file renaming and more.

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.