I'm trying to find a script that would basically look recusively at a directory, and if the script finds file that are .flac files, it will create a subfolder called FLAC in that same folder, and move the .flac files only into that directory. It may find 30 flac files in the same directory, so I don't want it to meltdown once it realizes the folder already exists, etc...

Example folder/file layout:

  • Base path is

  • Subdirectories currently look like

  • Files appear as

    /files/music/artist/album1/01-song 1.mp3
    /files/music/artist/album1/01-song 1.flac
    /files/music/artist/album1/02-another song.mp3
    /files/music/artist/album1/02-another song.flac
    /files/music/artist/album2/01-yet another.mp3
    /files/music/artist/album2/01-yet another.flac
  • So essentially I want it to become:

    /files/music/artist/album1/02-another song.mp3
    /files/music/artist/album1/flac/01-song 1.flac
    /files/music/artist/album1/flac/02-another song.flac
    /files/music/artist/album2/01-yet another.mp3
    /files/music/artist/album2/flac/01-yet another.flac

The whole idea, is that after scanning in a ton of my CDs, I have a lot of folders with mixed versions...so media players end up playing the song song twice (first the mp3 version, then the flac version)...

Is it possible to script something that would leave the directory as-is, if no mp3 files exist? (only flac?) Thus, if a folder had solely .flac files, it wouldn't create a subfolder...leave it as-is. The only hiccup I would see would be that it would have to look for mp3 files, as there might be other files in the folders (jpg cover files, etc..)

  • DayOff - that's what I'd use (assuming you're in files): find . -type d -exec sh -c 'ls "$0"/*.mp3 >/dev/null 2>&1 && ls "$0"/*.flac >/dev/null 2>&1 && mkdir "${0}/FLAC" && mv "${0}"/*.flac "${0}/FLAC"' {} \; - it's not very efficient but it should work with all kinds of file names / dir names. Add echo before mkdir and before mv to see what it does without actually running those commands. Commented May 30, 2015 at 22:01
  • Only hiccup I noticed is that it didn't handle variations of .FLAC (Case sensitivity)
    – DayOff
    Commented May 31, 2015 at 1:09
  • Yeah... to handle those too just run (before that command) shopt -s nocaseglob if you're using bash or unsetopt CASE_GLOB if you're using zsh. Commented May 31, 2015 at 9:06

3 Answers 3


An easy version that always creates flac and mp3 subdirectories (unless they would be empty), using the find command to execute a script to create a subdirectory if necessary and move the file there:

find . -name '*.mp3' -o -name '*.flac' -exec sh -c 'mkdir -p "${0%/*}/${0##*.}" && mv "$0" "${0%/*}/${0##*.}"' {} \;

For each file for which the shell snippet is executed, $0 is the path to the file, ${0%/*} is the directory part and ${0##*.} is the extension.

Alternatively, in bash (or ksh93 with set -o globstar instead of shopt -s globstar extglob, or in zsh without setopt ksh_glob instead), using the ** pattern:

shopt -s globstar extglob
for x in **/*.@(mp3|flac); do
  mkdir -p "${x%/*}/${x##*.}" && mv "$x" "${x%/*}/${x##*.}"

Now let's make a version that doesn't create a subdirectory if all the files have the same extension. Here it's easier to recurse on the directories. This is for bash (it can be adapted to ksh93 or zsh). In each directory, the script collects the list of all files (excluding . and ..), all.flacfiles and all.mp3files in arrays. If there is at least one flac file and at least one non-flac files, move the flac files to aflac` subdirectory. Ditto for mp3 files.

shopt -s globstar nullglob; GLOBIGNORE=.:..
for dir in "$PWD"/**/*/; do
  cd "$dir"
  if ((${#flac_files[@]} > 0 && ${#flac_files[@]} < ${#files[@]})); then
    mkdir flac && mv "${flac_files[@]}" flac/
  if ((${#mp3_files[@]} > 0 && ${#mp3_files[@]} < ${#files[@]})); then
    mkdir mp3 && mv "${mp3_files[@]}" mp3/
cd "$start_wd"

Use this:


find /files/music/artist -type f -name '*.flac' | while IFS= read -r file; do
    dir="$(dirname "$file")"
    file="$(basename "$file")"
    shopt -s nullglob
    mp3s=( "$dir"/*.mp3 )

    if ! [[ ${#mp3s[@]} -eq 0 ]]; then
        mkdir -p "$dir/$ext" && mv -i "$dir/$file" "$dir/$ext"
  • find will find files having .flac extension in the mentioned directory and all its subdirectories.

  • dir will contain the directory names of the files and file will have the file name

  • Then we have checked if that directory has any .mp3 file, if not then the files will remain as it is in the directory

  • If there is any .mp3 file in that directory, then a directory having the name of the extension (flac) will be created and .flac files will moved to that directory.

  • This runs dirname, basename, and a glob for each FLAC file. It's rather inefficient.
    – lcd047
    Commented May 30, 2015 at 19:28
  • @lcd047 Why do you think that dirname, basename result in inefficiency ?
    – heemayl
    Commented May 30, 2015 at 22:17
  • Why do you think they don't? They are external processes, and you run them for every single FLAC file.
    – lcd047
    Commented May 31, 2015 at 4:16

You have a bit complicated requirements, but this script might help.


run() {
        if $DRYRUN; then
                echo -n +
                printf " '%s'" "$@"

if test x"$1" = x-d; then

for dir in "$@"; do 
        find "$dir" -type d |
        while read subdir; do
                if ls "$subdir"/*.flac >/dev/null 2>&1; then
                        if ls "$subdir"/*.mp3 >/dev/null 2>&1; then
                                run mkdir -p "$subdir"/flac
                                run mv "$subdir"/*.flac "$subdir"/flac

You can see what will be going on by specifying -d. Be sure double-check it before actual moves.

$ ./script.sh -d /files/music
+ 'mkdir' '-p' '/files/music/artist/album2/flac'
+ 'mv' '/files/music/artist/album2/01-yet another.flac' '/files/music/artist/album2/flac'
+ 'mkdir' '-p' '/files/music/artist/album1/flac'
+ 'mv' '/files/music/artist/album1/01-song 1.flac' '/files/music/artist/album1/02-another song.flac' '/files/music/artist/album1/flac'

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .