Bash – Problem with ffmpeg in bash loop

bashffmpeg

When running the following command line to convert multiple .mkv files into .mp4 files, things go awry. It's as if the script tries to run all the commands at once or they get entangled in each other somehow, and the output gets messy. I don't know exactly. When I ran this just now, only the first file was converted. Other times, I seem to get unexpected or random results.

ls -1 *.mkv | while read f; do ffmpeg -i "$f" -codec copy "${f%.*}.mp4"; done

However, if I do the following, things work as expected:

ls -1 *.mkv | while read f; do echo ffmpeg -i \"$f\" -codec copy \"${f%.*}.mp4\"; done > script; bash script

But why? What is it with ffmpeg? This doesn't happen with bash loops and other commands than ffmpeg. I'd like to do it a simple way without escaping quotes, piping to a script file, etc.

Best Answer

ffmpeg reads from standard input as well, consuming data meant for read. Redirect its input from /dev/null:

... | while read f; do ffmpeg -i "$f" -codec copy "${f%.*}.mp4" < /dev/null; done

That said, don't read the output from ls like this. A simple for loop will suffice (and remove the original problem).

for f in *.mkv; do
    ffmpeg -i "$f" -codec copy "${f%.*}.mp4"
done
Related Question