1

I’ve got a weird situation. I have 100s of folders with flac and mp3 copies of the same tracks. I need to separate the mp3s from the flacs and put them into similarly named directories.

for example:

Album A : flac+mp3 >> Album A : flac
                      Album A : mp3

I am on a Unix system. How can I use the command line to achieve this?

  • Can you tell the files apart by their name (*.mp3 vs. *.flac)? Are the files in just one directory or in a directory tree? Shall the tree be restored in the target directories? – Hauke Laging Mar 17 '14 at 1:03
  • files have the exact same names but different extensions. One is flac and one is mp3. The directory tree is one root folder containing 100s of subfolders for each album – john Mar 17 '14 at 1:06
  • Are you actually running Unix or did you mean Linux? My answer uses some features that are specific to Linux and the bash shell, if that's not what you are using please edit and update your post. – terdon Mar 17 '14 at 3:05
  • I don't understand what you want to do, please give an example. Do you want to move foo.mp3 to foo/foo.mp3, or to mp3/foo.mp3, or something else? Do the target directories already exist or do they need to be created? – Gilles Mar 17 '14 at 20:08
3

This little scriptlet will do what you want. Run it from the directory that contains your Music (you can copy/paste directly into the terminal and hit Enter):

## Find all subdirectories of the current directory and 
## iterate through them, saving their name in the $d variable.
## There are various tricks used here to deal with spaces and
## weird characters in file names. See http://mywiki.wooledge.org/BashFAQ/020
find . -type d -print0 | while IFS= read -r -d '' dir; do

    ## Create the $dir/mp3 and $dir/flac directories
    ## unless they exist
    mkdir -p "$dir"/{mp3,flac}

    ## Move all mp4 files to $dir/mp3
    mv "$dir"/*.mp3 "$dir"/mp3 2>/dev/null

    ## Move all flac files to $dir/flac
    mv "$dir"/*.flac "$dir"/flac 2>/dev/null

    ## The previous steps will also create an artist/mp3 and 
    ## artist/flac directories, and if there were no files in
    ## the artist directory (only in the albums) these will be empty.
    ## This deletes them safely since rmdir will only remove empty ones.
  rmdir "$dir"/{flac,mp3} 2>/dev/null
done

The command above will transform this:

├── artist1
│   ├── album1
│   │   ├── file1.flac
│   │   ├── file1.mp3
│   │   ├── file2.flac
│   │   └── file2.mp3
│   └── album2
│       ├── file1.flac
│       ├── file1.mp3
│       ├── file2.flac
│       └── file2.mp3
└── artist2
    ├── album1
    │   ├── file1.flac
    │   ├── file1.mp3
    │   ├── file2.flac
    │   └── file2.mp3
    └── album2
        ├── file1.flac
        ├── file1.mp3
        ├── file2.flac
        └── file2.mp3

to this:

├── artist1
│   ├── album1
│   │   ├── flac
│   │   │   ├── file1.flac
│   │   │   └── file2.flac
│   │   └── mp3
│   │       ├── file1.mp3
│   │       └── file2.mp3
│   └── album2
│       ├── flac
│       │   ├── file1.flac
│       │   └── file2.flac
│       └── mp3
│           ├── file1.mp3
│           └── file2.mp3
└── artist2
    ├── album1
    │   ├── flac
    │   │   ├── file1.flac
    │   │   └── file2.flac
    │   └── mp3
    │       ├── file1.mp3
    │       └── file2.mp3
    └── album2
        ├── flac
        │   ├── file1.flac
        │   └── file2.flac
        └── mp3
            ├── file1.mp3
            └── file2.mp3
  • This at least does WHAT I WANTED, and works as advertised. However, how to run it a second time (probably after adding more music files), without creating a further set of subdirectories? – Marcel Aug 17 '15 at 20:19
  • @Marcel this shouldn't create any new subdirectories if the correctly named ones already exist. – terdon Sep 3 '15 at 12:22
2

You can do this with find, mkdir, and mv. First you create the necessary directories:

cd /target/dir/mp3
# the next line produces output which explains what's happening
find /source/dir -mindepth 1 -type d -printf "%P\0" | xargs -0 echo mkdir
find /source/dir -mindepth 1 -type d -printf "%P\0" | xargs -0 mkdir

Each directory under the source root is created under the target root. And then again, for the other group of files:

cd /target/dir/flac
find /source/dir -mindepth 1 -type d -printf "%P\0" | xargs -0 mkdir

Check if this does what you want:

find /source/dir -mindepth 1 -type d -printf "%P\0" | 
  xargs -0 -n 1 bash -c \
  'cd /source/dir/"$1"; echo mv -t "/target/dir/mp3/$1" *.mp3' bash-mv

Due to the echo it's not dangerous but shows what would happen (if the echo is deleted): For every directory under the source root the current directory is changed to it and mv is called for all files of the respective type in that directory. The complicated -printf | xargs bash -c structure is due to the fact that ... I didn't realize earlier that it is possible easier:

cd /source/dir
find . -mindepth 1 -type d -exec bash -c 'echo mv -t "/target/dir/mp3/{}" "{}"/*.mp3' \;

The shell is still needed for *.mp3 expansion.

  • I think the OP wants to create artist/albumA/flac and artist/albumA/mp3 subdirectories in each dir and move the files into these subdirectories, not all together in a single one. At least, that's what's shown in the diagram in the OP. Plus, this is likely to result in data loss since many files could have the same name (track1.mp3 etc). – terdon Mar 17 '14 at 3:50
  • @terdon I find the OP diagram not very precise. My idea was: two root dirs for mp3 and flac and beneath the tree: artist/albumA. My /target/dir/mp3 is just the root. There would not be file name collisions because each dir's content is moved to a separate dir. – Hauke Laging Mar 17 '14 at 4:42

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.