Что делает перенаправление "2 <& 1" в оболочке Bourne?

2>&1 redirect в оболочке Bourne выводит результат, отправленный в дескриптор файла 2 (по умолчанию, стандартную ошибку) и отправляет его вместо этого в файл дескриптор 1 (по умолчанию стандартный вывод).

Но что делает перенаправление 2<&1?

Он отправляет stderr в stdin?

Моя теория заключалась в том, что она отправляла stdin в stderr (например, такой же, как 1>&2), но экспериментально, это не так:

$ perl -e 'print "OUT\n"; print STDERR "ERR\n"; \
  while (<>) { print "IN WAS $_\n";}'           \
  > out3 2<&1
df
$ cat out3
ERR
OUT
IN WAS df

Обратите внимание, что стандартная ошибка и стандартная ошибка обоих отправились в файл out3, где stdout был перенаправлен.

Ответ 1

Оператор <& дублирует дескриптор файла ввода. Согласно IEEE Std 1003.1-2001 (aka Single Unix Specification v3, преемник POSIX), предполагается, что это ошибка, чтобы сказать 2<&1, если 1 не является файловым дескриптором, открытым для ввода. Тем не менее, похоже, что bash ленив и не заботится, открыт ли дескриптор файла для ввода или вывода.

Итак, как 2<&1, так и 2>&1 просто выполните системный вызов dup2(1, 2), который копирует дескриптор файла 1 в дескриптор файла 2.

Вы можете проверить, выполнив такую ​​команду, так как перенаправления выполняются слева направо:

sleep 99999 1>/dev/null 2<&1

Затем в другом окне запустите lsof в процессе sleep. Вы увидите, что оба файловых дескриптора 1 и 2 указывают на /dev/null. Пример (на моем 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 -2
sleep   8869 mayoff    1w   CHR    3,2       0t0       316 /dev/null
sleep   8869 mayoff    2w   CHR    3,2       0t0       316 /dev/null

Ответ 2

Рассматривая код анализатора в источнике для Bash, кажется, что 2>&1 обрабатывается так же, как 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);
        }

Просматривая источник перенаправления redir.c, константы r_duplicating_input и r_duplicating_output, похоже, обрабатываются одинаково. То же, что и в make_redirection в make_cmd.c.

Тестирование с помощью простой программы, которая выводит "yay" на stdout и "nay" на stderr, я могу подтвердить ваши результаты теста:

$ ./a.out > out 2>&1
$ cat out
nay
yay
$ ./a.out > out 2<&1
$ cat out
nay
yay
$ ./a.out > out 1>&2
yay
nay
$ cat out
$ ./a.out > out 1<&2
yay
nay
$ cat out
$

Ответ 3

От man bash в разделе 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.

Таким образом, в случае 2 < 1, кажется, что 2 (stderr) делается копией 1 (stdout). Я протестировал его другим способом 1<&2, чтобы stdout являлся копией stderr.

Итак, в тестовой программе:

#!/bin/bash
echo hello 1<&2

При запуске в командной строке hello выводится на stderr not stdout

$ ./test > /dev/null
hello
$ ./test > /dev/null 2>&1
$