Search code examples
bashgrepfindflac

More elegant use of find for passing files grouped by directory?


This script has taken me too long (!!) to compile, but I finally have a reasonably nice script which does what I want:

find "$@" -type d -print0 | while IFS= read -r -d $'\0' dir; do
    find "$dir" -iname '*.flac' -maxdepth 1 ! -exec bash -c '
        metaflac --list --block-type=VORBIS_COMMENT "$0" 2>/dev/null | grep -i "REPLAYGAIN_ALBUM_PEAK" &>/dev/null
        exit $?
    ' {} ';' -exec bash -c '
        echo Adding ReplayGain tags to "$0"/\*.flac...
        metaflac --add-replay-gain "${@:1}"
    ' "$dir" {} '+'
done

The purpose is to search the file tree for directories containing FLAC files, test whether any are missing the REPLAYGAIN_ALBUM_PEAK tag, and scan all the files in that directory for ReplayGain if they are missing.

The big stumbling block is that all the FLAC files for a given album must be passed to metaflac as one command, otherwise metaflac doesn't know they're all one album. As you can see, I've achieved this using find ... -exec ... +.

What I'm wondering is if there's a more elegant way to do this. In particular, how can I skip the while loop? Surely this should be unnecessary, because find is already iterating over the directories?


Solution

  • I can't comment on the flac commands themselves, but as for the rest:

    find . -name '*.flac' \
     ! -exec bash -c 'metaflac --list --block-type=VORBIS_COMMENT "$1" | grep -qi "REPLAYGAIN_ALBUM_PEAK"' -- {} \; \
      -execdir bash -c 'metaflac --add-replay-gain *.flac' \;
    

    You just find the relevant files, and then treat the directory it's in.