Consider the following sample script:
#!/bin/sh
do_something() {
echo $@
return 1
}
cat <<EOF > sample.text
This is a sample text
It serves no other purpose
EOF
cat sample.text | while read arg1 arg2 arg3 arg4 arg5; do
ret=0
do_something "$arg1" "$sarg2" "$arg3" "$arg4" "$arg5" <&3 || ret=$?
done 3<&1
What is the purpose of redirecting stdout
as input for filedescriptor 3?
At least in Bash
, it does not seem to make any difference if omitted. Does it have any effect if it is executed in any other shell than bash
?
UPDATE
For those wondering where this is from, it is a simplified sample from Debian's cryptdisks_start
script.
The clear intent here is to prevent do_something
from reading from the sample.text
stream, by ensuring that its stdin is coming from elsewhere. If you're not seeing differences in behavior with or without the redirection, that's because do_something
isn't actually reading from stdin in your tests.
If you had both read
and do_something
reading from the same stream, then any content consumed by do_something
wouldn't be available to a subsequent instance of read
-- and, of course, you'd have illegitimate contents fed on input to do_something
, resulting in consequences such as a bad encryption key being attempted (if the real-world use case were something like cryptmount
), &c.
cat sample.text | while read arg1 arg2 arg3 arg4 arg5; do
ret=0
do_something "$arg1" "$sarg2" "$arg3" "$arg4" "$arg5" <&3 || ret=$?
done 3<&1
Now, it's buggy -- 3<&1
is bad practice compared to 3<&0
, inasmuch as it assumes without foundation that stdout is something that can also be used as input -- but it does succeed in that goal.
By the way, I would write this more as follows:
exec 3</dev/tty || exec 3<&0 ## make FD 3 point to the TTY or stdin (as fallback)
while read -a args; do ## |- loop over lines read from FD 0
do_something "${args[@]}" <&3 ## |- run do_something with its stdin copied from FD 3
done <sample.text ## \-> ...while the loop is run with sample.txt on FD 0
exec 3<&- ## close FD 3 when done.
It's a little more verbose, needing to explicitly close FD 3, but it means that our code is no longer broken if we're run with stdout attached to the write-only side of a FIFO (or any other write-only interface) rather than directly to a TTY.
As for the bug that this practice prevents, it's a very common one. See for example the following StackOverflow questions regarding it:
etc.