Я пытаюсь понять, как состояние выхода передается при использовании канала. Предположим, я использую, which
чтобы найти несуществующую программу:
which lss
echo $?
1
Поскольку which
не удалось найти, lss
я получил статус выхода 1. Это нормально. Однако, когда я пытаюсь следующее:
which lss | echo $?
0
Это указывает на то, что последняя выполненная команда завершилась нормально. Единственный способ понять это - возможно, PIPE также выдает статус выхода. Это правильный способ понять это?
bash
shell-script
pipe
exit
sshekhar1980
источник
источник
which lss | echo $?
,echo
начинается доwhich
выхода; оболочка, генерирующая командную строку для,echo
не имеет возможности узнать, каким будет состояние выходаwhich
позже.Ответы:
Состояние выхода конвейера - это состояние выхода последней команды в конвейере (если в оболочках,
pipefail
которые его поддерживают, не установлена опция оболочки, в этом случае статус выхода будет такой же, как у последней команды в конвейере, которая завершается с ненулевой статус).Невозможно вывести состояние выхода конвейера из конвейера, так как нет никакого способа узнать, каким будет это значение, пока конвейер фактически не завершит выполнение.
Трубопровод
не имеет смысла, так
echo
как не читает свой стандартный ввод (конвейеры используются для передачи данных между выводом одной команды на вход следующей).echo
Также не печатает статус выхода трубопровода, а статус выхода команды немедленно бежать до того трубопровода.Это лучший пример:
Это означает, что конвейер также может использоваться с
if
:источник
Состояние выхода канала - это состояние выхода правой команды. Статус выхода левой команды игнорируется.
(Обратите внимание, что
which lss | echo $?
это не показано. Вы должны запустить,which lss | true; echo $?
чтобы показать это. Inwhich lss | echo $?
,echo $?
сообщает о состоянии последней команды перед этим конвейером.)Причина, по которой оболочки ведут себя таким образом, заключается в том, что существует довольно распространенный сценарий, в котором ошибку в левой части следует игнорировать. Если правая сторона выходит (или, в более общем случае, закрывает свой стандартный ввод), в то время как левая сторона все еще пишет, то левая сторона получает сигнал SIGPIPE. В этом случае обычно нет ничего плохого: правая сторона не заботится о данных; если роль левой стороны состоит исключительно в том, чтобы производить эти данные, тогда можно остановить их.
Однако, если левая сторона умирает по какой-либо причине, отличной от SIGPIPE, или если работа левой стороны заключалась не только в создании данных на стандартном выводе, то ошибка в левой стороне является подлинной ошибкой, которая должно быть сообщено.
В простом sh единственным решением является использование именованного канала.
В ksh, bash и zsh вы можете указать оболочке сделать выход конвейера с ненулевым состоянием, если какой-либо компонент конвейера завершится с ненулевым состоянием. Вам нужно установить
pipefail
опцию:set -o pipefail
shopt -s pipefail
setopt pipefail
(илиsetopt pipe_fail
)В mksh, bash и zsh вы можете получить статус каждого компонента конвейера, используя переменную
PIPESTATUS
(bash, mksh) илиpipestatus
(zsh), которая является массивом, содержащим статус всех команд в последнем конвейере (обобщение$?
).источник
Да, PIPE выдает статус выхода; если вы хотите код выхода команды перед ТРУБОЙ, вы можете использовать
$PIPESTATUS
В соответствии с этими вопросами и ответами по переполнению стека , чтобы напечатать состояние выхода команды при использовании канала, вы можете сделать:
Или установите pipefail с помощью команды
set -o pipefail
(чтобы сбросить, сделайтеset +o pipefail
) и используйте$?
вместо$PIPESTATUS
.Эти команды работают только после того, как вы запустите их хотя бы один раз; это означает, что
PIPESTATUS
работает только тогда, когда вы запускаете его после команды с конвейером, например так:Вы получите 10 за
${PIPESTATUS[0]}
и 1 за${PIPESTATUS[1]}
. Смотрите U & L Q & A для получения дополнительной информации.источник
PIPESTATUS
на то, что содержит состояния выхода команд в последнем конвейере, ваш первый пример не имеет больше смысла, чем тотsomecmd | echo $?
, который Кусалананда рассмотрел в своем ответе.false; true | echo $PIPESTATUS
печать1
для состояния выходаfalse
.|exho
это действительно сбивает с толкуОболочка оценивает командную строку перед выполнением конвейера. Таково
$?
значение последней команды, выполненной перед конвейером. Независимо от тогоecho
, запущен ли сам до или послеwhich
.Теперь, если ваш вопрос был конкретно о распространении статуса выхода, вы можете изучить поведение по умолчанию, например:
Как вы можете видеть, состояние выхода конвейера - это состояние выхода его последней команды.
источник