Search code examples
bashmacosdirectory

Creating folders based on part of a filename


I have a bunch of audiobooks in one folder on macOS. The file naming structure is Author - Title.m4b (e.g. JRR Tolkien - Lord of the Rings.m4b). I would like to run a bash script and then have the following folder structure:

  • Author (folder)

  • --> Title (folder)

  • ----> Audiobook m4b file (naming as above, unchanged)

So the file would be in the book folder in the author folder.

I have found this script:

find . -type f -name "*jpg" -maxdepth 1 -exec bash -c 'mkdir -p "${0%%_*}"' {} \; \
-exec bash -c 'mv "$0" "${0%%_*}"' {} \;

But it "only" takes the author as a folder and puts the file in there. I have not found a way to take the title and make this another subfolder level.


Solution

  • With your given file name structure, with sh, mkdir and mv something like this:

    #!/bin/sh
    
    for file in ./*.m4b; do
      author="${file%% *}"
      file_name="${file##* }"
      title="${file_name%.*}"
      echo mkdir -p "$author/$title" &&
      echo mv -v "$file" "$author/$title/$file_name"
    done
    

    Output:

    mkdir -p ./Author/Title
    mv -v ./Author - Title.m4b ./Author/Title/Title.m4b
    

    Without all the echo , the output is like this on my side:

    renamed './Author - Title.m4b' -> './Author/Title/Title.m4b'
    

    This should handle your file names with spaces.

    #!/bin/sh
    
    for file in ./*.m4b; do
      author=${file%% -*}
      file_name=${file##*- }
      title=${file_name%.*}
      echo mkdir -p "$author/$title" &&
      echo mv -v "$file" "$author/$title/$file_name"
    done
    

    with bashv4+ with the =~ operator.

    #!/bin/bash
    
    regexp='^(.+) - (.*)\.(.+)$'
    for file in ./*.m4b; do
      [[ $file =~ $regexp ]] &&
      author=${BASH_REMATCH[1]}
      title=${BASH_REMATCH[2]}
      file_name=${BASH_REMATCH[2]}.${BASH_REMATCH[3]}
      echo mkdir -p "$author/$title" &&
      echo mv -v "$file" "$author/$title/$file_name"
    done
    

    Output:

    mkdir -p ./Author/Title
    mv -v ./Author - Title.m4b ./Author/Title/Title.m4b
    mkdir -p ./Dan Brown/Diabolus
    mv -v ./Dan Brown - Diabolus.m4b ./Dan Brown/Diabolus/Diabolus.m4b
    mkdir -p ./JRR Tolkien/Lord of the Rings
    mv -v ./JRR Tolkien - Lord of the Rings.m4b ./JRR Tolkien/Lord of the Rings/Lord of the Rings.m4b
    

    Without the echo

    renamed './Author - Title.m4b' -> './Author/Title/Title.m4b'
    renamed './Dan Brown - Diabolus.m4b' -> './Dan Brown/Diabolus/Diabolus.m4b'
    renamed './JRR Tolkien - Lord of the Rings.m4b' -> './JRR Tolkien/Lord of the Rings/Lord of the Rings.m4b'
    
    • Remove all the echo if you're satisfied with the output.

    Output from the tree utility:

    Author/
    └── Title
        └── Title.m4b
    Dan Brown/
    └── Diabolus
        └── Diabolus.m4b
    JRR Tolkien/
    └── Lord of the Rings
        └── Lord of the Rings.m4b
    
    3 directories, 3 files