Configurar pipefail para un solo comando canalizado


18

Necesito ejecutar varios comandos de shell canalizados desde un script que no sea BASH (es decir, un script PHP) como estos:

command1 | command2 | command3

de modo que, si command1falla con un código de salida distinto de cero, cada otro comando también falla. Hasta ahora, lo que se me ocurrió es:

set -o pipefail && command1 | command2 | command3

Pero a pesar de que se ejecuta bien desde la terminal, produce esto si se ejecuta desde el script:

sh: 1: conjunto: opción ilegal -o pipefail


Parece que /bin/shno le gusta set -o pipefail. ¿Está realmente bashdisfrazado o es un caparazón diferente? Cuando bashse ejecuta como /bin/sh, ¿acepta set -o pipefail?
— Jonathan Leffler

@JonathanLeffler Cuando lo ejecuto /bin/sh set -o pipefaildice /bin/sh: 0: Can't open set(lo mismo con sudo). Espero haberlo probado bien. El sistema es Ubuntu 12.
— Desmond Hume

Tendrías que intentarlo /bin/sh -c "set -o pipefail"; tal como estaba, el shell intentaba ejecutar un script en el directorio actual llamado sety no lo encontró.
— Jonathan Leffler

@JonathanLeffler /bin/sh -c "set -o pipefail"no funciona, sin embargo, bash -c "set -o pipefail"sí.
— Desmond Hume

Entonces, su problema es que el script es ejecutado por /bin/shlo que no reconoce set -o pipefail. En consecuencia, deberá asegurarse de que el script se ejecute en /bin/bashlugar de hacerlo /bin/sh. O, si tiene confianza, valiente, y probablemente insensato, cambie /bin/shpara ser un enlace o copia de, en /bin/bashlugar de cualquier shell al que esté vinculado actualmente o una copia. Si está seguro de que /bin/shes así bash, está utilizando un comportamiento que bashno se expone cuando se ejecuta como /bin/sh; usar bashcomo bash.
— Jonathan Leffler

Respuestas:


18

Desde la línea de comando Bash, debería invocar una subshell para evitar que pipefailse establezca después:

$ (set -o pipefail && command1 | command2 | command3)

Esto limitaría el efecto de la pipefailopción al subshell creado por los paréntesis (...).

Un verdadero ejemplo:

$ (set -o pipefail && false | true) && echo pipefail inactive || echo pipefail active
pipefail active

Si usa una llamada de shell explícita con la -copción, no necesita una subshell, ya sea con basho con un shalias para bash:

$ bash -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active
$ sh -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active

Como su shno acepta la pipefailopción, tendría que suponer que se trata de una versión anterior o modificada de bash, o que en realidad es algún otro shell por completo.


1
¿Es $en la primera pieza una parte del comando, es solo un indicador de shell? Intenté en ambos sentidos, realmente no funcionó. La bash -cforma siempre funciona, aunque no demasiado elegante ...
— Desmond Hume

5

No estoy seguro de por qué no se mencionó anteriormente, pero es posible desarmar explícitamente pipefail, usando set +o pipefail.

set -o pipefail
command1 | command2 | command3
set +o pipefail

Si está ejecutando un fragmento y no está seguro acerca del pipefailconjunto ya configurado, puede usar esto con la subshell como se sugirió anteriormente:

# explicitly execute with pipefail set
(set -o pipefail ; command1 | command2 | command3 )
# explicitly execute with pipefail unset
(set +o pipefail ; command1 | command2 | command3 )

0

Puede usar $ (comando1) combinado con $? :

a=$(echo "a")
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

Imprime "abc"

a=$(ls unexitingDir)
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

Imprime "".

"[$? -eq 0] &&" significa que el siguiente comando se ejecuta solo si el anterior tuvo éxito.

Eso no responde a su pregunta, pero es una solución a su problema.


¿Significa que siempre necesitaría almacenar la salida de cada uno de los comandos en una variable?
— Desmond Hume

Siempre no lo sé, pero con mi solución sí lo hará (si lo necesita para su próximo comando). A menos que pueda escribircommand1 && command2 && command3
— cglacet
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.