What does "2<&1" redirect do in Bourne shell?
The <&
operator duplicates an “input” file descriptor. According to IEEE Std 1003.1-2001 (aka Single Unix Specification v3, the successor to POSIX), it's supposed to be an error to say 2<&1
if 1 is not a file descriptor open for input. However, it appears that bash
is lazy and doesn't care if the file descriptor is open for input or for output.
So both 2<&1
and 2>&1
simply perform the system call dup2(1, 2)
, which copies file descriptor 1 to file descriptor 2.
You can check by running a command like this, since redirections are performed left-to-right:
sleep 99999 1>/dev/null 2<&1
Then in another window, run lsof
on the sleep
process. You'll see that both file descriptors 1 and 2 point to /dev/null
. Example (on my Mac):
:; ps axww | grep sleep 8871 s001 R+ 0:00.01 grep sleep 8869 s003 S+ 0:00.01 sleep 99999:; lsof -p 8869 | tail -2sleep 8869 mayoff 1w CHR 3,2 0t0 316 /dev/nullsleep 8869 mayoff 2w CHR 3,2 0t0 316 /dev/null
Looking at the parser code in the source for Bash, it seems that 2>&1
is treated in the same way as 2<&1
.
parse.y
| NUMBER LESS_AND NUMBER { redir.dest = $3; $$ = make_redirection ($1, r_duplicating_input, redir); }...| NUMBER GREATER_AND NUMBER { redir.dest = $3; $$ = make_redirection ($1, r_duplicating_output, redir); }
Looking through the redirection source redir.c
, the constants r_duplicating_input
and r_duplicating_output
seem to be treated in the same way. Same as in the make_redirection
function in make_cmd.c
.
Testing with a simple program that prints "yay" to stdout and "nay" to stderr, I can confirm your test results:
$ ./a.out > out 2>&1$ cat outnayyay$ ./a.out > out 2<&1$ cat outnayyay$ ./a.out > out 1>&2yaynay$ cat out$ ./a.out > out 1<&2yaynay$ cat out$
From man bash
under REDIRECTION:
Duplicating File Descriptors 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 descrip‐ tor. 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.
So in the case of 2<&1, it seems that 2
(stderr) is made to be a copy of 1
(stdout). I've tested it with the other way around 1<&2
makes stdout to be a copy of stderr.
So in a test program:
#!/bin/bashecho hello 1<&2
When run on command line, hello is output to stderr not stdout
$ ./test > /dev/nullhello$ ./test > /dev/null 2>&1$