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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…