7

I basically want to go from this:

.
├── Alan Walker
│   ├── Different World
│   │   ├── 01 Intro.mp3
│   │   ├── 02 Lost Control.mp3
│   │   └── cover.jpg
│   └── Same World
│       ├── 01 Intro.mp3
│       └── 02 Found Control.mp3
├── Aurora
│   └── Infections Of A Different Kind Step 1
│       ├── 01 Queendom.lrc
│       ├── 02 Forgotten Love.lrc
│       └── 03 Gentle Earthquakes.mp3
└── Guns N' Roses
    └── Use Your Illusion I
        ├── 01 Right Next Door To Hell.lrc
        ├── 01 Right Next Door To Hell.mp3
        ├── 02 Dust N' Bones.lrc
        └── 02 Dust N' Bones.mp3

to this:

.
├── Alan Walker - Different World
│   ├── 01 Intro.mp3
│   ├── 02 Lost Control.mp3
│   └── cover.jpg
├── Alan Walker - Same World
│   ├── 01 Intro.mp3
│   └── 02 Found Control.mp3
├── Aurora - Infections Of A Different Kind Step 1
│   ├── 01 Queendom.lrc
│   ├── 02 Forgotten Love.lrc
│   └── 03 Gentle Earthquakes.mp3
└── Guns N' Roses - Use Your Illusion I
    ├── 01 Right Next Door To Hell.lrc
    ├── 01 Right Next Door To Hell.mp3
    ├── 02 Dust N' Bones.lrc
    └── 02 Dust N' Bones.mp3

None of the existing solutions I could find included renaming the directory itself. It'd be great to be able to do this with zmv, but I can't figure out how to.

  • 2
    Not a full solution, so not an answer: easytag may let you do this, but only for audio files - I don't think it will move covers, etc. – rvs Jan 2 '19 at 14:34
  • 2
    Could there be more than one album for a specific artist within one artist directory? Is the structure always three levels deep? – nohillside Jan 2 '19 at 14:52
  • 1
    @nohillside Yes, There can be more than one album for an artist. And yes, the structure is always three levels deep. – aksh1618 Jan 2 '19 at 14:54
9

Zsh

Untested:

zmv -Q '(*)/(*)(/)' '$1 - $2'
rmdir -- *(/^F)

The second line removes all empty directories, even those that didn't have a file before. It's possible to work around this with a custom mv wrapper that records what directories it moves things from.

Note that this traverses symbolic links to directories in the current directory.

Linux rename utility

Untested.

rename / ' - ' */*/
rmdir -- */ 2>/dev/null

Note that this traverses symbolic links to directories in the current directory and in its subdirectories. The second line removes all empty directories, even those that didn't have a file before.

Perl rename script

Untested.

prename 's~/~ - ~' */*/
rmdir -- */ 2>/dev/null

Note that this traverses symbolic links to directories in the current directory and in its subdirectories. The second line removes all empty directories, even those that didn't have a file before.

Here's a more complex approach that only removes directories that it renamed something from. Again, untested.

prename 's~([^/]+)/~$1 - ~ and ++$d{$1}; END {map {rmdir} keys %d}' */*/
| improve this answer | |
12

Something like this maybe?

#!/bin/sh

for topdir in */; do
    topdir_name=$( basename "$topdir" )

    for subdir in "$topdir"/*/; do
        subdir_name=$( basename "$subdir" )

        newdir="$topdir_name - $subdir_name"
        if mkdir "$newdir"; then
            mv "$subdir"/* "$newdir"
            rmdir "$subdir"
        fi
    done

    rmdir "$topdir"
done

This goes through all the top-level directories in the current directory (the band names). For each such directory, it goes through its subdirectories (the album names). For each pair of band name and album name, a new directory is created and the files from the subdirectory are moved to it. The album subdirectories are removed when they have been processed, as are the original band top-level directories.

The rmdir calls will fail if any directory contains hidden filenames or if any of the new directories failed to be created.

This is totally untested code. Run it on a backed-up copy of your files.

| improve this answer | |
  • I mean, yes, something like would work, but I'm kinda looking for a one or two line solution, to run easily from terminal. Some find/sed/zmv magic :) – aksh1618 Jan 2 '19 at 15:06
  • 10
    Put ot into a script, and -boom- it becomes a one-liner. – Hans-Martin Mosner Jan 2 '19 at 15:24
  • Yes, it does, but deep down I'll always know. – aksh1618 May 31 at 8:38
  • @aksh1618 Well, deep down you also know that a simple command are several (possibly hundreds or thousands of) lines of C code. There is no real difference. The point is that if you create a complex script, you encapsulate the complexity for the ease of use from the command line. – Kusalananda May 31 at 9:28
4

Strategically, rather than moving files, have you considered leaving the current structure in place and creating links for the new structure you want?

Tactically, a pattern that'll do the job goes like this:

find . -mindepth 2 -maxdepth 2 -type d -print0 | xargs -0n1 bash -c \
  'b=$(basename "$(dirname "$1")"); a=$(basename "$1"); echo ln -s "$1" "$b-$a"' {}
  • find locates all directories exactly two levels deep from the current working directory, which should be the directory containing the bands: thus two levels deep are the album names underneath the band names.1
  • xargs consumes each path containing an album and calls out to the inline bash script.
  • bash -c '...' takes the album path as its first argument, breaking that path into two parts: the band ($b) and the album ($a). Finally, the script reassembles the names into the desired format and links the new directory name to the original directory.

Note that, in this example, the links would be created in the same directory from which you start, which also happens to be where the band names are.

You could - and should - tweak the ln strategy above to match your intent. mv with the right paths if you physically want to rearrange, or ln if you're wanting to create a convenience "view" over the media. The important parts inside the bash script are:

  • $b the band name. Always quote it: "$b".
  • $a the album name. Always quote it: "$a".
  • $1 the physical path to the album directory. Always quote it: "$1".

1 I believe m{ax,in}depth are supported by GNU and some BSD find, but not POSIX: in which case, rely on */* or similar shell gymnastics.

| improve this answer | |
  • 1
    I like this answer... you could also make hardlinks, then delete the old folder structure when you're satisfied – Thomas Zwaagstra Jan 2 '19 at 20:20
  • @ThomasZwaagstra That's no different than moving the files – Darkhogg Jan 3 '19 at 10:53
  • 1
    @Darkhogg Exactly! OP was looking for a 1-liner to move the files. Using hardlinks with this solution would nearly accomplish that, except you would have an intermediate "preview" stage before deleting the original files – Thomas Zwaagstra Jan 3 '19 at 23:15

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.