Mass file conversion using find and exec
Table of Contents
convert mp3 to opus
The short solution
find ./ -type f -name '*.mp3' -exec sh -c 'ffmpeg -i "{}" -f wav - | opusenc --music - "{}.opus"' \;
The full journey to the solution
The first trick was just to use ffmpeg
to convert to .wav, and then to take that .wav output and feed it to opusenc
1 ffmpeg -i input.mp3 -f wav - | opusenc –bitrate 256 - output.opus
find ./ -name ‘*.wma’ -type f | sed ‘s,\.wma$,.mp3,’
Works for finding and listing all:
find ./ -type f -name '*.mp3' -exec echo {} +
ffmpeg Worked for one
In two steps I was able to convert one target to an opus file.
ffmpeg -i "11 John Harrison with the Wichita State University Chamber Players - Winter Mvt 2 Largo.mp3" -f wav "11 Winter Mvt 2 Largo.wav"
and then
opusenc --music "11 Winter Mvt 2 Largo.wav" "11 Winter Mvt 2 Largo.opus"
at once:
ffmpeg -i "12 John Harrison with the Wichita State University Chamber Players - Winter Mvt 3 Allegro.mp3" -f wav - | opusenc --music - "12 John Harrison with the Wichita State University Chamber Players - Winter Mvt 3 Allegro.opus"
What I didn’t realize is that piping is something the shell is doing, which would come to give me troubles in wrapping this in to find -exec
.
Try for multiple
find ./ -type f -name '*.mp3' -exec ffmpeg -i "\{\}" -f wav "\{\}.wav" +
# find: missing argument to `-exec'
Problem: can’t get the syntax right for `find exec` (multiple files, .mp3 to .opus)
I have mp3 files that I want to convert to opus, all at once. The right tool for the job should be find
, but I can’t get the syntax to work. What is working for just one:
ffmpeg -i "12 John Harrison with the Wichita State University Chamber Players - Winter Mvt 3 Allegro.mp3" -f wav - | opusenc --music - "12 John Harrison with the Wichita State University Chamber Players - Winter Mvt 3 Allegro.opus"
Obviously the filenames are a mouthful so I would like find
to take care of that for me2. But here is my attempt, and the failure I can’t seem to get past:
find ./ -type f -name '*.mp3' -exec 'ffmpeg -i "\{\}" -f wav - | opusenc --music - "\{\}.opus"' +
# find: missing argument to `-exec'
Works without error but prints output to stdout. Notice the use of sh in the -exec
block3:
find ./ -type f -name '*.mp3' -exec sh -c 'ffmpeg -i "{}" -f wav -' \;
Success!
trying to put the output right, and it all worked! It was suprisingly fast, taking only some seconds on my machine (again, only a dozen files were here).
find ./ -type f -name '*.mp3' -exec sh -c 'ffmpeg -i "{}" -f wav - | opusenc --music - "{}.opus"' \;
Bonus: renaming with emacs dired edit
As you could guess from the code, my process produced the directory of .mp3.opus filenames, which is a bit unseemly. I open the directory in dired and fire up dired-toggle-read-only
(which I have bound to C-c C-r
in dired buffers) and do a quick replace of “.mp3.opus” to “.opus” and save the changes. dired-toggle-read-only
is a very handy command that I use frequently.
Bonus 2: Filesize
Converting to from .mp3 to .opus was not motivated purely by filesize; there was mostly the compelling reason that opus is a better (and free²) format4 . Nonetheless it was gratifying to find that for just 12 files my opus conversion took 51M of .mp3 to just 33M of .opus; that conversion size savings rate of 33% (only 2/3rds the filesize of .opus) I would expect the progress to be much more significant for more than a trivial dozen mp3 files.
Footnotes
1 The process for a single-file is recommended here: https://askubuntu.com/questions/211054/how-to-convert-a-sound-file-to-opus
2 The linux command find
is good at inserting the found name into a command: https://unix.stackexchange.com/questions/60404/manipulate-file-name-piped-from-find-command
3 When piping is going to be done with find exec, you need to account for the fact that piping is a method provided by the shell, not by find; hence the need to include a shell -c
command. https://stackoverflow.com/questions/307015/how-do-i-include-a-pipe-in-my-linux-find-exec-command
4 Opus format is described at https://en.m.wikipedia.org/wiki/Opus_(audio_format) or, with more partiality, at https://opus-codec.org/ .