oarfish
oarfish

Reputation: 4641

Batch-process files with find in multiple directories

I have a directory with several subdirs which contain .flac files. I want to batch convert them to .mp3. The path names contain spaces. Now I want to do something like this

find . -type f -regex .*.flac -exec ffmpeg -i {} -c:a mp3 -b:a 320k  \;

But the question is, how can I use {} and substitute flac for mp3 to give ffmpeg an output file name? In bash, one could use variable substitution ${file%.flac}.mp3, but I cannot apply this here. sed-based approaches don't seem to work with find either. Is there any simple solution to this?

Upvotes: 2

Views: 375

Answers (2)

gniourf_gniourf
gniourf_gniourf

Reputation: 46903

If you really want to use find (e.g., you're stuck in the past with an antique version of Bash and globstar isn't available — so using Tom Fenech's solution is not an option), you have to spawn a shell to do the substitution. The standard way would be:

find . -name '*.flac' -type f -exec sh -c 'ffmpeg -i "$1" -c:a mp3 -b:a 320k  "${1%.flac}.mp3"' dummy {} \;

sh -c will run its first argument, and the subsequence arguments are set to the positional parameters starting from 0. That's why I put a dummy parameter (and I called it dummy, but anything else could do).

Note that in find's -name, the argument *.flac needs to be quoted. For some reason you edited your post and replaced the -name predicate with a -regex predicate: it's really useless, and you still need to quote the argument anyways.

Upvotes: 2

Tom Fenech
Tom Fenech

Reputation: 74695

If you're using bash, I'd use globstar, which will expand to the list of all your .flac files:

shopt -s globstar nullglob
for file in **/*.flac; do
    [[ -f $file ]] || continue
    out_file=${file%.flac}.mp3
    ffmpeg # your options here, using "$out_file"
done

The check [[ -f $file ]] skips any directories that end in .flac. You could probably skip this if you don't have any of those.

I've also enabled the nullglob shell option, so that a pattern which doesn't match any files expands to nothing (so the loop won't run).

Upvotes: 4

Related Questions