Estoy tratando de entender cómo se comunica el estado de salida cuando se usa una tubería. Supongamos que estoy usando whichpara localizar un programa inexistente:
which lss
echo $?
1
Como whichno lsspude localizar , obtuve un estado de salida de 1. Esto está bien. Sin embargo, cuando intento lo siguiente:
which lss | echo $?
0
Esto indica que el último comando ejecutado ha salido normalmente. La única forma en que puedo entender esto es que quizás PIPE también produce un estado de salida. ¿Es esta la forma correcta de entenderlo?
bash
shell-script
pipe
exit
sshekhar1980
fuente
fuente

which lss | echo $?,echose inicia antes de quewhichhaya salido; el shell que genera la línea de comandoechono tiene forma posible de saber cuálwhichserá el estado de salida de más adelante.Respuestas:
El estado de salida de la tubería es el estado de salida del último comando en la tubería (a menos que la opción de shell
pipefailse establezca en los shells que lo admiten, en cuyo caso el estado de salida será el del último comando en la tubería que sale con un estado distinto de cero).No es posible generar el estado de salida de una tubería dentro de una tubería, ya que no hay forma de saber cuál sería ese valor hasta que la tubería haya terminado de ejecutarse.
La tubería
no tiene sentido ya
echoque no lee su entrada estándar (las tuberías se utilizan para pasar datos entre la salida de un comando a la entrada del siguiente). Elechotampoco habría imprimir el estado de salida de la tubería, pero el estado de salida del comando se ejecute inmediatamente antes de la tubería.Este es un mejor ejemplo:
Esto significa que una tubería también se puede usar con
if:fuente
El estado de salida de una tubería es el estado de salida del comando de la derecha. El estado de salida del comando de la izquierda se ignora.
(Tenga en cuenta que
which lss | echo $?no muestra esto. Usted correríawhich lss | true; echo $?para mostrar esto. Enwhich lss | echo $?,echo $?informa el estado del último comando antes de esta canalización).La razón por la cual los shells se comportan de esta manera es que hay un escenario bastante común en el que se debe ignorar un error en el lado izquierdo. Si el lado derecho sale (o más generalmente cierra su entrada estándar) mientras el lado izquierdo todavía está escribiendo, entonces el lado izquierdo recibe una señal SIGPIPE. En este caso, generalmente no hay nada de malo: el lado derecho no se preocupa por los datos; Si el papel del lado izquierdo es únicamente para producir estos datos, entonces está bien que se detenga.
Sin embargo, si el lado izquierdo muere por algún motivo que no sea SIGPIPE, o si el trabajo del lado izquierdo no era únicamente producir datos en la salida estándar, entonces un error en el lado izquierdo es un error genuino que debe ser reportado
En simple sh, la única solución es usar una tubería con nombre.
En ksh, bash y zsh, puede indicar al shell que realice una salida de canalización con un estado distinto de cero si algún componente de la canalización sale con un estado distinto de cero. Necesitas configurar la
pipefailopción:set -o pipefailshopt -s pipefailsetopt pipefail(osetopt pipe_fail)En mksh, bash y zsh, puede obtener el estado de cada componente de la tubería utilizando la variable
PIPESTATUS(bash, mksh) opipestatus(zsh), que es una matriz que contiene el estado de todos los comandos de la última tubería (una generalización de$?)fuente
Sí, PIPE produce un estado de salida; si desea el código de salida del comando antes del PIPE, puede usar
$PIPESTATUSDe acuerdo con estas preguntas y respuestas sobre el desbordamiento de pila , para imprimir el estado de salida de un comando cuando utiliza una tubería, puede hacer lo siguiente:
O configure pipefail con el comando
set -o pipefail(para desarmarlo, hacerset +o pipefail), y use en$?lugar de$PIPESTATUS.Estos comandos solo funcionan después de ejecutarlos al menos una vez; eso significa que
PIPESTATUSsolo funciona cuando lo ejecutas después del comando con la tubería, así:Obtendrá 10 por
${PIPESTATUS[0]}y 1 por${PIPESTATUS[1]}. Consulte estas preguntas y respuestas de U&L para obtener más información.fuente
PIPESTATUScontiene los estados de salida de los comandos en la última tubería, su primer ejemplo no tiene más sentido que elsomecmd | echo $?que Kusalananda trató en su respuesta.false; true | echo $PIPESTATUSimprime1para el estado de salida defalse.|exhoque realmente está confundiendoEl shell evalúa la línea de comando antes de ejecutar la tubería. Entonces, ¿
$?es el valor del último comando ejecutado antes de la canalización? Siechose inicia antes o despuéswhiches irrelevante.Ahora, si su pregunta era específicamente sobre la propagación del estado de salida, puede estudiar el comportamiento predeterminado de esta manera:
Como puede ver, el estado de salida de una tubería es el estado de salida de su último comando.
fuente