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.
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'
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
./*.m4b
to its absolute path.