Состояние выхода канала - это состояние выхода правой команды. Статус выхода левой команды игнорируется.
(Обратите внимание, что which lss | echo $?
это не показано. Вы должны запустить, which lss | true; echo $?
чтобы показать это. In which lss | echo $?
, echo $?
сообщает о состоянии последней команды перед этим конвейером.)
Причина, по которой оболочки ведут себя таким образом, заключается в том, что существует довольно распространенный сценарий, в котором ошибку в левой части следует игнорировать. Если правая сторона выходит (или, в более общем случае, закрывает свой стандартный ввод), в то время как левая сторона все еще пишет, то левая сторона получает сигнал SIGPIPE. В этом случае обычно нет ничего плохого: правая сторона не заботится о данных; если роль левой стороны состоит исключительно в том, чтобы производить эти данные, тогда можно остановить их.
Однако, если левая сторона умирает по какой-либо причине, отличной от SIGPIPE, или если работа левой стороны заключалась не только в создании данных на стандартном выводе, то ошибка в левой стороне является подлинной ошибкой, которая должно быть сообщено.
В простом sh единственным решением является использование именованного канала.
set -e
mkfifo p
command1 >p & pid1=$!
command2 <p
wait $pid1
В ksh, bash и zsh вы можете указать оболочке сделать выход конвейера с ненулевым состоянием, если какой-либо компонент конвейера завершится с ненулевым состоянием. Вам нужно установить pipefail
опцию:
- КШ:
set -o pipefail
- Баш:
shopt -s pipefail
- зш:
setopt pipefail
(или setopt pipe_fail
)
В mksh, bash и zsh вы можете получить статус каждого компонента конвейера, используя переменную PIPESTATUS
(bash, mksh) или pipestatus
(zsh), которая является массивом, содержащим статус всех команд в последнем конвейере (обобщение $?
).
which lss | echo $?
,echo
начинается доwhich
выхода; оболочка, генерирующая командную строку для,echo
не имеет возможности узнать, каким будет состояние выходаwhich
позже.