I'm writing a Bash script in which I read a file line by line ( well, <(find /home/user/ -iname "*.MP4")
to be exact ) , and for each line I execute ffmpeg
, so I'm doing something like this:
while read -r line; do
ffmpeg -i "$line" [ MORE OPTIONS ... ]
done < <(find /home/user/ -iname "*.MP4")
Though, for some reason, only the first line is being processed successfuly.
Any idea why my code ignores all other lines ?
That's a frequent problem which is caused by the special behavior of ffmpeg
(also happens with ssh
).
Quoted from Bash FAQ 89 which handles your case almost exactly:
What's happening here? Let's take the first example. read reads a line from standard input (FD 0), puts it in the file parameter, and then ffmpeg is executed. Like any program you execute from BASH, ffmpeg inherits standard input, which for some reason it reads. I don't know why. But in any case, when ffmpeg reads stdin, it sucks up all the input from the find command, starving the loop.
TL;DR :
There are two main options:
Adding a </dev/null
at the end of ffmpeg
's line ( i.e. ffmpeg -i "$line" [ MORE OPTIONS ] ... </dev/null
) will fix the issue and will make ffmpeg
behave as expected.
Let read
read from a File Descriptor which is unlikely to be used by a random program:
while IFS= read -r line <&3; do
# Here read is reading from FD 3, to which 'file' is redirected.
done 3<file