Estoy tratando de entender cómo se comunica el estado de salida cuando se usa una tubería. Supongamos que estoy usando which
para localizar un programa inexistente:
which lss
echo $?
1
Como which
no lss
pude 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 $?
,echo
se inicia antes de quewhich
haya salido; el shell que genera la línea de comandoecho
no tiene forma posible de saber cuálwhich
será 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
pipefail
se 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
echo
que 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). Elecho
tampoco 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
pipefail
opción:set -o pipefail
shopt -s pipefail
setopt 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
$PIPESTATUS
De 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
PIPESTATUS
solo 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
PIPESTATUS
contiene 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 $PIPESTATUS
imprime1
para el estado de salida defalse
.|exho
que 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? Siecho
se inicia antes o despuéswhich
es 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