Atribuindo código de saída a uma variável local do shell

42
#!/bin/bash
function0()
{
 local t1=$(exit 1)
 echo $t1
}

function0

echoimprime valor vazio. Eu esperava:

1

Por que a t1variável não recebe o valor de retorno do comando exit - 1?

Gilles 'SO- parar de ser mau'
fonte

Respostas:

58

local t1=$(exit 1) diz ao shell para:

  • executar exit 1em um subshell;
  • armazene sua saída (como em, o texto que ele gera na saída padrão) em uma variável t1, local para a função.

Portanto, é normal que t1acabe vazio.

( $()é conhecido como substituição de comando .)

O código de saída é sempre atribuído a $?, para que você possa

function0()
{
  (exit 1)
  echo "$?"
}

para obter o efeito que você está procurando. É claro que você pode atribuir $?a outra variável:

function0()
{
  (exit 1)
  local t1=$?
  echo "$t1"
}
Stephen Kitt
fonte
11
Você sabe, você sempre pode colocar o retorno no cano também. `$ (trap 'printf" :: ERRNO: $? "' 0; # agora faça o que for necessário - essa armadilha garantirá que a última string escrita seja o último retorno para todo o contexto de substituição.
mikeserv
11
@mikeserv você perdeu um backtick? $(trap 'printf "::ERRNO:$?"' 0; # now do whatever however
Doktor J
12

O código de saída foi armazenado em $? variável. Usando a Substituição de Comando captura apenas a saída, você deve usar (...) para criar o subshell :

#!/bin/bash

func() {
  (exit 1)
  local t1=$?
  printf '%d\n' "$t1"
}

func
cuonglm
fonte
o objetivo da tarefa t1=$?é usá-lo, não? e não seria $?derrotado pela operação op? Eu acho que eu estou perguntando se ele não deve serprintf '%d\n' "${t1}"
Dani_l
@Dani_l: Obrigado, isso é um erro de digitação. Atualizada.
precisa saber é
Observe que a substituição de comando captura apenas o padrão, a menos que seja redirecionado de maneira diferente.
Phyatt #
7

Em bashisso funciona:

loc(){  local   "x=$(exit "$1"):$?"
        printf  '$%s:\t%d\n' \
                 x "${x##*:}" \? "$?"
}

Tem a ver com a ordem de avaliação do comando e a atribuição de variáveis. localpossui um valor de retorno próprio - e é o comando em execução no momento, não a substituição do comando. A razão pela qual coisas como ...

x=$(exit 1); echo "$?"

... pode retornar 1 é porque nunca há um retorno nesse comando, exceto para a execução do subshell para atribuir $xo valor - portanto $?, não é prejudicado, como acontece em praticamente todos os outros casos em que as substituições de comando são usadas.

De qualquer forma, com localque se destroçada - mas se você pegá-lo no momento certo - que é, enquanto as expansões ainda estão sendo avaliados e antes de local 's rotinas têm a chance de espancar ele - você ainda pode atribuí-lo.

unset x; loc 130; echo "${x-\$x is unset}"

... imprime ...

$x: 130
$?: 0
$x is unset

No entanto, você deve saber que, em muitos reservatórios, você não pode confiar $?nesse tipo de avaliação. De fato, isso provavelmente ocorre porque essas conchas não se incomodam em reavaliar a cada momento possível, como talvez bash- o que eu diria que é provavelmente um comportamento melhor do que basho seu. Deseja realmente que o seu intérprete avalie valores de loop recursivamente que provavelmente serão substituídos antes que você tenha a chance de usá-los?

Enfim, é assim que você pode fazer isso.

mikeserv
fonte
-1

Dependendo do motivo pelo qual você está tentando obter o código de saída, também é possível executar o if some-command; then echo "Success $?"; else echo "Failure $?"; fique não faz nada com a saída do comando, apenas avalia o código de saída da execução do comando. Você pode adicionar or( or$ ( around the command and you'll still get the same results. A better example might bese grep -q 'somestring' somefile; então echo "O código de saída encontrado é $?"; Else "Não encontrou o código de saída é $?"; Fi`.

Você também pode testar o código de retorno de uma função que pode ser um return 3código de retorno explícito ou implícito, que é o resultado do último comando; nesse caso, você precisa ter cuidado para não ter um echono final do , caso contrário, mascara / redefine o código de saída anterior.

command_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
}
command_last; echo $?
# Outputs:
# True is 0
# False is 1
# 1

echo_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
  # echo'ing literally anything (or nothing) returns true aka exit 0
  echo
}
echo_last; echo $?
# Outputs:
# True is 0
# False is 1
#            # Blank line due to empty echo
# 0

Finalmente, um truque sujo, já que você não pode fazer, VAR=(SOME_COMMAND)porque VAR=()é uma definição de matriz que você precisa VAR=( $(echo 'Some value') ).

dragon788
fonte
Todas as saídas reivindicadas estão erradas, devido ao fato de a substituição de comando não fornecer o código de saída, que é o ponto principal da questão. Não está claro o que o "truque sujo" tem a ver com qualquer coisa.
Nick Matteo