Состояние выхода канала - это состояние выхода правой команды. Статус выхода левой команды игнорируется.
(Обратите внимание, что 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позже.