Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I know you can create a file descriptor and redirect output to it. e.g.

exec 3<> /tmp/foo # open fd 3.
echo a >&3 # write to it
exec 3>&- # close fd 3.

But you can do the same thing without the file descriptor:

FILE=/tmp/foo
echo a > "$FILE"

I'm looking for a good example of when you would have to use an additional file descriptor.

share|improve this question
add comment

4 Answers 4

up vote 16 down vote accepted

Most commands have a single input channel (standard input, file descriptor 0) and a single output channel (standard output, file descriptor 1) or else operate on several files which they open by themselves (so you pass them a file name). (That's in addition from standard error (fd 2), which usually filters up all the way to the user.) It is however sometimes convenient to have a command that acts as a filter from several sources or to several targets. For example, here's a simple script that separtes the odd-numbered lines in a file from the even-numbered ones

while IFS= read -r line; do
  printf '%s\n' "$line"
  if IFS= read -r line; then printf '%s\n' "$line" >&3; fi
done >odd.txt 3>even.txt

Now suppose you want to apply a different filter to the odd-number lines and to the even-numbered lines (but not put them back together, that would be a different problem, not feasible from the shell in general). In the shell, you can only pipe a command's standard output to another command; to pipe another file descriptor, you need to redirect it to fd 1 first.

{ while … done | odd-filter >filtered-odd.txt; } 3>&1 | even-filter >filtered-even.txt

Another, simpler use case is filtering the error output of a command.

exec M>&N redirects a file descriptor to another one for the remainder of the script (or until another such command changes the file descriptors again). There is some overlap in functionality between exec M>&N and somecommand M>&N. The exec form is more powerful in that it does not have to be nested:

exec 8<&0 9>&1
exec >output12
command1
exec <input23
command2
exec >&9
command3
exec <&8

Other examples that may be of interest:

And for even more examples:

P.S. This is a surprising question coming from the author of the most upvoted post on the site that uses redirection through fd 3!

share|improve this answer
    
I'd rather say that "most commands have either single or double output channel - stdout (fd 1) and very often stderr (fd 2)". –  rozcietrzewiacz Aug 17 '11 at 15:15
    
Also, could you by the way explain why you use while IFS= read -r line;? The way I see it, IFS has no effect here since you assign value to only one variable (line). See this question. –  rozcietrzewiacz Aug 17 '11 at 15:33
    
@rozcietrzewiacz I've made a mention of stderr, and see the first part of my answer for why IFS makes a difference even if you're reading a into single variable (it's to retain the leading whitespace). –  Gilles Aug 18 '11 at 1:26
add comment

In the context of named pipes (fifos) the use of an additional file descriptor can enable non-blocking piping behaviour.

(
rm -f fifo
mkfifo fifo
exec 3<fifo   # open fifo for reading
trap "exit" 1 2 3 15
exec cat fifo | nl
) &
bpid=$!

(
exec 3>fifo  # open fifo for writing
trap "exit" 1 2 3 15
while true;
do
    echo "blah" > fifo
done
)
#kill -TERM $bpid

See: Named Pipe closing prematurely in script?

share|improve this answer
    
you dug up one of my old questions :) chad is right, you'll run into a race condition. –  MaxMackie Aug 17 '11 at 11:57
add comment

Here's yet another scenario when using an additional file descriptor seems appropriate (in Bash):

Shell script password security of command-line parameters

env -i bash --norc   # clean up environment
set +o history
read -s -p "Enter your password: " passwd
exec 3<<<"$passwd"
mycommand <&3  # cat /dev/stdin in mycommand
share|improve this answer
add comment

An extra file descriptor is good for when you want to catch the stdout in a variable yet still want to write out to the screen, for instance in a bash script user interface

arg1 string to echo 
arg2 flag 0,1 print or not print to 3rd fd stdout descriptor   
function ecko3 {  
if [ "$2" -eq 1 ]; then 
    exec 3>$(tty) 
    echo -en "$1" | tee >(cat - >&3)
    exec 3>&- 
else 
    echo -en "$1"  
fi 
}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.