Что делает &> делать в bash?

Я смотрел на крючок перед фиксацией и обнаружил следующую строку, потому что мне было интересно, почему у меня всегда есть файл empy под названием 1 в моем каталоге после совершения фиксации.

git status 2&>1 > /dev/null

Я считаю, что намерение состоит в том, чтобы написать следующее, и я исправил его.

git status 2>&1 > /dev/null

Однако мне было любопытно, что делает следующий синтаксис, поэтому я просмотрел справочную страницу.

git status 2&>1

Вот страница man.

  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 equiva‐
      lent to

             >word 2>&1

Однако, эта страница руководства подразумевает, что эти два эквивалента, что, похоже, не так.

Может ли кто-нибудь прояснить справочную страницу и объяснить, что именно происходит с этим синтаксисом?

Ответы

Ответ 1

Здесь используются операторы:

  • > Синтаксис: file_descriptor opt> имя_файла
  • >& Синтаксис: file_descriptor opt>& file_descriptor
  • &> Синтаксис: &> имя_файла

Если дескриптор файла опущен, по умолчанию используется 0 (стандартный ввод) для ввода или 1 (стандартный вывод) для вывода. 2 означает stderr.

Итак, мы имеем:

  • >name означает 1>name - перенаправить стандартный вывод на name файла
  • &>name похоже на 1>name 2>name - перенаправляет stdout и stderr на name файла (однако name открывается только один раз; если вы на самом деле написали 1>name 2>name оно попытается открыть name дважды и, возможно, произойдет сбой).

Поэтому, когда вы пишете git status 2&>1, это значит, что git status 2 1>1 2>1, т.е.

  • первые 2 фактически передаются в качестве аргумента для git status.
  • stdout перенаправляется в файл с именем 1 (не дескриптор файла 1)
  • stderr перенаправляется в файл с именем 1

Эта команда должна на самом деле создать файл с именем 1 содержимое которого является результатом состояния git status 2 то есть состояние файла с именем 2 которое, вероятно, является "Ваша ветка устарела, ничего не нужно фиксировать, рабочий каталог очищен", предполагая вы на самом деле не отслеживаете файл с именем 2.

Ответ 2

&>word>&word перенаправляет как stdout, так и stderr в результат разложения слова. В вышеприведенных случаях это файл 1.

2>&1 перенаправляет stderr (fd 2) на текущее значение stdout (fd 1). (Выполнение этого перед перенаправлением stdout позже в строке не делает то, что вы ожидаете, и будет разделять выходы вместо того, чтобы держать их в сочетании и является очень распространенной ошибкой сценария оболочки. Сравните это с >word 2>&1, который объединяет два fds в одна отправка в том же месте.)

$ { echo stdout; echo stderr >&2; }
stdout
stderr
$ { echo stdout; echo stderr >&2; } >/dev/null
stderr
$ { echo stdout; echo stderr >&2; } >/dev/null 2>&1
$ 
{ echo stdout; echo stderr >&2; } 2>&1 >/dev/null
stderr

Не то, чтобы они были похожи, но не одно и то же.

git status 2&>1 > /dev/null фактически фактически работает git status 2 с перенаправлением &>1 (stdout и stderr в файл 1). Почти наверняка не то, что предназначалось. Ваша коррекция почти наверняка является тем, что было предназначено.

$ git init repro
Initialized empty Git repository in /tmp/repro/.git/
$ cd repro/
$ git status
# On branch master
#
# Initial commit
#
nothing to commit
$ ls
$ git status 2>&1
# On branch master
#
# Initial commit
#
nothing to commit
$ ls
$ git status 2&>1
$ ls
1
$ cat 1
# On branch master
#
# Initial commit
#
nothing to commit