Como obtenho a saída e o valor de saída de um subshell ao usar “bash -e”?

54

Considere o seguinte código

outer-scope.sh

#!/bin/bash
set -e
source inner-scope.sh
echo $(inner)
echo "I thought I would've died :("

inner-scope.sh

#!/bin/bash
function inner() { echo "winner"; return 1; }

Estou tentando fazer com que outer-scope.sh saia quando uma chamada para inner() falhar. Como $() invoca um sub-shell, isso não acontece.

Como eu obtenho a saída de uma função enquanto preservo o fato de que a função pode sair com um código de saída diferente de zero?

    
por jabalsad 01.12.2011 / 14:22

3 respostas

82

$() preserva o status de saída; você só precisa usá-lo em uma declaração que não tenha status próprio, como uma atribuição.

output=$(inner)

Depois disso, $? conterá o status de saída de inner e você poderá usar todos os tipos de verificações para ele:

output=$(inner) || exit $?
echo $output

Ou:

if ! output=$(inner); then
    exit $?
fi
echo $output

Ou:

if output=$(inner); then
    echo $output
else
    exit $?
fi

(Nota: Um exit sem argumentos equivale a exit $? - ou seja, ele sai com o status de saída do último comando. Eu usei o segundo formulário apenas para clareza).

Além disso, para o registro: source é completamente não relacionado neste caso. Você pode definir apenas inner() no arquivo outer-scope.sh , com os mesmos resultados.

    
por 01.12.2011 / 14:46
21

Veja BashFAQ / 002 :

If you want both (output, and exit status):

output=$(command)
status=$? 

Um caso especial

Note sobre um caso complicado com variáveis locais de função, compare o seguinte código:

f() { local    v=$(echo data; false); echo output:$v, status:$?; }
g() { local v; v=$(echo data; false); echo output:$v, status:$?; }

Recebemos:

$ f     # fooled by 'local' with inline initialization
output:data, status:0

$ g     # a good one
output:data, status:1

Por quê?

Quando a saída de um subshell é usada para inicializar uma variável local , o status de saída não é mais do subshell, mas do local < em> comando , que é mais provável que seja 0 .

Veja também link

    
por 21.07.2016 / 21:26
4
#!/bin/bash
set -e
source inner-scope.sh
foo=$(inner)
echo $foo
echo "I thought I would've died :("

Ao adicionar echo , o subshell não está sozinho (não é verificado separadamente) e não aborta. A atribuição contorna esse problema.

Você também pode fazer isso e redirecionar a saída para um arquivo, para depois processá-lo.

tmpfile=$( mktemp )
inner > $tmpfile
cat $tmpfile
rm $tmpfile
    
por 01.12.2011 / 14:35

Tags