1708
Comment: read -r
|
2151
<file => < file
|
Deletions are marked like this. | Additions are marked like this. |
Line 5: | Line 5: |
{{{ | {{{#!highlight bash |
Line 8: | Line 8: |
ffmpeg -i "$file" -vcodec libxvid -acodec libfaac -ar 32000 "${file%.avi}".mkv | ffmpeg -i "$file" -c:v libx264 -c:a aac "${file%.avi}".mkv |
Line 12: | Line 12: |
{{{ | {{{#!highlight bash |
Line 16: | Line 16: |
done <hostslist | done < hostslist |
Line 21: | Line 21: |
Here's one way to make it work: {{{ |
Use the `-nostdin` global option in `ffmpeg` to disable interaction on standard input: {{{#!highlight bash |
Line 24: | Line 24: |
ffmpeg -i "$file" -vcodec libxvid -acodec libfaac -ar 32000 "${file%.avi}".mkv </dev/null | ffmpeg -nostdin -i "$file" -c:v libx264 -c:a aac "${file%.avi}".mkv |
Line 27: | Line 27: |
Notice the [[BashGuide/InputAndOutput#Redirection|redirection]] on the ffmpeg line: `</dev/null`. The ssh example can be fixed the same way, or with the `-n` switch (at least with [[http://www.openssh.org/|OpenSSH]]). |
Alternatively you could use [[BashGuide/InputAndOutput#Redirection|redirection]] at the end of the ffmpeg line: `</dev/null`. The ssh example can be fixed the same way, or with the `-n` switch (at least with [[http://www.openssh.org/|OpenSSH]]). |
Line 31: | Line 30: |
{{{ while read -r line <&3; do |
{{{#!highlight bash while IFS= read -r line <&3; do |
Line 34: | Line 33: |
done 3<file | done 3< file |
Line 36: | Line 35: |
In bash, the `read` builtin can also be told to read directly from an fd (`-u fd`) without redirection, and since bash 4.1, an available fd can be assigned (`{var}<file`) instead of hard coding a file descriptor. {{{#!highlight bash # bash 4.1+ while IFS= read -r -u "$fd" line; do ... done {fd}< file exec {fd}<&- }}} |
I'm reading a file line by line and running ssh or ffmpeg, only the first line gets processed!
When reading a file line by line, if a command inside the loop also reads stdin, it can exhaust the input file. For example:
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.
Use the -nostdin global option in ffmpeg to disable interaction on standard input:
Alternatively you could use redirection at the end of the ffmpeg line: </dev/null. The ssh example can be fixed the same way, or with the -n switch (at least with OpenSSH).
Sometimes with large loops it might be difficult to work out what's reading from stdin, or a program might change its behaviour when you add </dev/null to it. In this case you can make read use a different FileDescriptor that a random program is less likely to read from:
In bash, the read builtin can also be told to read directly from an fd (-u fd) without redirection, and since bash 4.1, an available fd can be assigned ({var}<file) instead of hard coding a file descriptor.