Что делает &> делать в 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