5

I am struggling with understanding IO redirection in bash. I have seen many examples like the following (which is literally taken from the accepted answer here):

exec 3<> /tmp/foo  #open fd 3.
echo "test" >&3
exec 3>&- #close fd 3.

I don't understand the second line. To be precise, I don't understand how its behavior is in accordance with the bash manual.

Obviously, in the second line, >&3 should redirect stdout (and possibly stderr - I don't know) to file descriptor 3; everything else wouldn't make any sense.

But from the current bash manual (at the time of writing), section 3.6.4 (formatting mine):

This construct allows both the standard output (file descriptor 1) and the standard error output (file descriptor 2) to be redirected to the file whose name is the expansion of word. There are two formats for redirecting standard output and standard error:
&>word and >&word

[ It then explains subtle differences between the first and the second format, but let's put this aside for a moment because it is not important for the question. ]

To my understanding this says that >&3 redirects stderr and stdout to a file whose name is 3, which is quite different from redirecting stdout (and possibly stderr) to file descriptor 3.

Could anybody please explain what I am missing?

1

1 Answer 1

16

Actually, it's precisely the bit you put aside that is most relevant (from the GNU bash documentation):

3.6.4 Redirecting Standard Output and Standard Error

This construct allows both the standard output (file descriptor 1) and the standard error output (file descriptor 2) to be redirected to the file whose name is the expansion of word.

There are two formats for redirecting standard output and standard error:

&>word 

and

>&word 

Of the two forms, the first is preferred. This is semantically equivalent to

>word 2>&1 

When using the second form, word may not expand to a number or ‘-’. If it does, other redirection operators apply (see Duplicating File Descriptors below) for compatibility reasons.

That final note is the most important bit, so I will repeat it here:

When using the second form, word may not expand to a number or ‘-’. If it does, other redirection operators apply (see Duplicating File Descriptors below) for compatibility reasons.

So if word expands to a number or -, special rules are triggered. Strings expand to themselves, so 3 can be said to "expand" to 3 which means that >&3 is treated according to the rules described in the Duplicating File Descriptors section:

The redirection operator

[n]<&word 

is used to duplicate input file descriptors. If word expands to one or more digits, the file descriptor denoted by n is made to be a copy of that file descriptor. If the digits in word do not specify a file descriptor open for input, a redirection error occurs. If word evaluates to ‘-’, file descriptor n is closed. If n is not specified, the standard input (file descriptor 0) is used.

The operator

[n]>&word 

is used similarly to duplicate output file descriptors. If n is not specified, the standard output (file descriptor 1) is used. If the digits in word do not specify a file descriptor open for output, a redirection error occurs. If word evaluates to ‘-’, file descriptor n is closed. As a special case, if n is omitted, and word does not expand to one or more digits or ‘-’, the standard output and standard error are redirected as described previously.

All this to say that in the specific case where what comes after the >& is a number, that number is assumed to be a file descriptor. Presumably, this is precisely why the manual states that &>word is preferred over the equivalent >&word since &>word is unambiguous.

4
  • Thanks a lot, +1 and accepted. That one really got me. Actually, I had stopped thinking about the part I had put aside (i.e. the difference between the two formats) when I head read the three words it ends with: "for compatibility reasons". Normally, I don't care about compatibility because bash in reasonably recent versions is the only shell I currently use, and thus, I usually don't put time in subjects that are tagged "compatibility". So I have learned an important lesson and will do this in the future. Thanks again!
    – Binarus
    Apr 5, 2023 at 16:56
  • 3
    @Binarus, If I'm not mistaken, >& in the sense "redirect both stdout and stderr" is from csh, while >&- and >&NN are likely from some other Bourne-like shell (perhaps ksh), and they do conflict a bit. The latter ones are codified in POSIX (and they're much more useful in general, and can be used to compose the other meaning), so Bash has to give priority to them. I'm not sure about &>, it could be just a Bash-specific shorthand invented exactly because it doesn't clash that directly with the others. (It means something different but pretty much useless other shells)
    – ilkkachu
    Apr 5, 2023 at 17:28
  • @ilkkachu Thank you very much for that in-depth explanation!
    – Binarus
    Apr 5, 2023 at 18:16
  • @Binarus: You've now learned something: "for compatibility reasons" is a shorthand for "we think this behavior is inconsistent and/or stupid, but we can't change it because it was first implemented like this 40 years ago and now millions of programs depend on it." Apr 6, 2023 at 21:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .