Configurando o pipefail para um único comando canalizado


13

Eu preciso executar um número de comandos do shell canalizado de um script não-BASH (ou seja, script PHP) como estes:

command1 | command2 | command3

de modo que, se command1 falha com um código de saída diferente de zero, o outro comando também falha. Até agora, o que eu tenho é:

set -o pipefail && command1 | command2 | command3

Mas apesar de funcionar bem no terminal, ele produz isso se executado a partir do script:

sh: 1: set: Opção ilegal -o pipefail


Parece que /bin/sh não gosta set -o pipefail. É realmente bash disfarçado, ou é uma casca diferente? Quando bash é executado como /bin/shaceita set -o pipefail?
Jonathan Leffler

@JonathanLeffler Quando eu corro /bin/sh set -o pipefail diz /bin/sh: 0: Can't open set (mesma coisa com sudo ). Espero ter testado direito. O sistema é o Ubuntu 12.
Desmond Hume

Você precisaria tentar /bin/sh -c "set -o pipefail"; como estava, o shell estava tentando executar um script no diretório atual chamado set e não encontrou.
Jonathan Leffler

@ JonathanLeffler /bin/sh -c "set -o pipefail" não está funcionando, no entanto bash -c "set -o pipefail" faz.
Desmond Hume

Então, seu problema é que o script é executado por /bin/sh que não reconhece set -o pipefail. Conseqüentemente, você precisará garantir que o script seja executado por /bin/bash ao invés de /bin/sh. Ou, se você estiver confiante, corajoso - e provavelmente imprudente - mude /bin/sh para ser um link para, ou cópia de, /bin/bash em vez de qualquer shell que esteja atualmente vinculado ou uma cópia dele. Se você tem certeza de que /bin/sh é bash, então você está usando um comportamento que bash não expõe quando executado como /bin/sh; usar bash Como bash.
Jonathan Leffler

Respostas:


14

Da linha de comando do Bash você precisaria invocar um subshell para evitar pipefail sendo definido depois:

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

Isso limitaria o efeito do pipefail opção para o subshell criar pelos parênteses (...).

Um exemplo real:

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

Se você usar uma chamada shell explícita com o -c opção você não precisa de um subshell, seja com bash ou com um sh alias 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

Desde o seu sh não aceita o pipefail opção, eu teria que assumir que é alguma versão mais antiga ou modificada de bash - ou que na verdade é alguma outra casca completamente.


1
É $ na primeira parte, uma parte do comando é apenas um prompt de shell? Tentei nos dois sentidos, realmente não funcionou. o bash -c maneira sempre funciona, não muito elegante tho ..
Desmond Hume

2

Não tenho certeza porque não foi mencionado acima, mas é possível explicitamente desfeito pipefailusando set +o pipefail.

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

Se você estiver executando um fragmento e não tiver certeza pipefail já definido, você pode usar isso com o subshell como sugerido anteriormente:

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

0

Você pode usar $ (command1) combinado com $? :

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] & amp; & amp;" significa que o seguinte comando é executado apenas se o anterior for bem sucedido.

Isso não responde à sua pergunta, mas é uma solução para o seu problema.


Isso significa que eu sempre precisaria armazenar a saída de cada um dos comandos em uma variável?
Desmond Hume

Sempre eu não sei mas com a minha solução sim você vai (se precisar para o próximo comando). A menos que você possa apenas escrever command1 && command2 && command3
Christian Glacet
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.