Search code examples
bashautomator

Make directory based on filenames before fourth underscore


I have these test files:

ABCD1234__12_Ab2_Hh_3P.mp4
ABCD1234__12_Ab2_Lw_3P.wmv
ABCD1234__12_Ab2_SSV.mov
EFGH56789__13_Mn1_SSV.avi
EFGH56789__13_Mn1_Ve1_3P.mp4
EFGH56789__13_Mn1_Ve2_3P.webm

I want to create a context service in Automator that makes directories based on the filename prefixes above like so:

ABCD1234__12_Ab2
EFGH56789__13_Mn1

...and move the files into those two accordingly. The only consistent variables in the names are underscores, so I was thinking I could delineate by those, preferably capturing the name before the fourth one.

I originally started with this very simple script:

for file in "$@"
do
mkdir "${file%.*}" && mv "$file" "${file%.*}"
done

Which makes a folder for every file and moves each file into its own folder.

I tried adding variables, various if/thens, etc. but to no avail (not a programmer by trade).

I also wrote another script to do it in a slightly different way, but with the same results to mess around with:

for folder in "$@"
do
cd "$1"
find . -type f -maxdepth 1 -exec bash -c 'mkdir -p "${0%.*}"' {} \; \
-exec bash -c 'mv "$0" "${0%.*}"' {} \;
done

I feel like there's something obvious I am missing.


Solution

  • Your script is splitting on dot, but you say you want to split on underscore. If the one you want to split on is the last one, the fix is trivial:

    for file in "$@"
    do
        mkdir -p "${file%_*}" && mv "$file" "${file%_*}"
    done
    

    To get precisely the fourth, try

    for file in "$@"
    do
        tail=${file#*_*_*_*_}
        dir=${file%_"$tail"}
        mkdir -p "$dir" && mv "$file" "$dir"
    done
    

    The addition of the -p option is a necessary bug fix if you want to use && here; mkdir without this option will fail if the directory already exists.

    Perhaps see also the section about parameter expansions in the Bash Reference Manual which explains this syntax and its variations.