Como fazer com que o `local` capture o código de saída?

11

No meu projeto, tenho o seguinte snippet:

local output="$(bash "${1##*/}")"
echo "$?"

Isso sempre imprime zero devido a local, no entanto, remover localfaz com que a $?variável se comporte corretamente: assumir o código de saída do subshell.

Minha pergunta é: como posso manter essa variável local enquanto captura o valor de saída?

Ultimate Hawk
fonte
1
shellchecknão apenas detectará esse problema, mas sugerirá a solução em unix.stackexchange.com/a/281749/24718 !
Waleed Khan

Respostas:

16
#!/bin/bash
thing() {
   local foo=$(asjkdh) ret="$?"
   echo "$ret"
}

Isso ecoará 127, o código de erro correto para "comando não encontrado".

Você pode usar localpara definir mais de uma variável. Então, apenas criei a variável local RETpara capturar o código de saída do subshell antes de ter localsucesso e definir $?como zero.

DopeGhoti
fonte
É garantido que bashavalie esta expressão da esquerda para a direita?
Max Ried
Tanto quanto sei, as atribuições de variáveis ​​estão em ordem, da esquerda para a direita neste contexto, sim.
DopeGhoti
@MaxRied O fato de isso funcionar de forma confiável parece indicar que sim, é. No entanto, não encontro informações sobre isso nem no bashmanual de referência do POSIX nem no manual.
cat
10
Como um aparte, o uso de nomes de variáveis ​​com maiúsculas é uma forma incorreta. Consulte a especificação da variável de ambiente POSIX em pubs.opengroup.org/onlinepubs/009695399/basedefs/… , que descreve os nomes em maiúsculas como reservados para variáveis ​​com significado para o shell ou sistema e nomes com pelo menos um caractere em minúsculas reservado para uso definido pelo aplicativo, tendo em mente que variáveis ​​de shell e variáveis ​​de ambiente compartilham um espaço para nome (uma vez que, no caso de colisões, a atribuição ao primeiro pode substituir o último).
Charles Duffy
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
terdon
27

Declare a variável local antes de atribuir a ela:

thing() {
  local output
  output="$(bash "${1##*/}")"
  echo "$?"
}

Na minha opinião, isso também é mais legível do que definir uma RETvariável adicional . YMMV nisso, mas funciona exatamente como você esperaria.

Curinga
fonte
2
Isso é muito melhor do que usar uma variável separada, como deve ser óbvio se você quiser verificar o código de retorno de várias tarefas: simplesmente local var1 var2 ...e Bob é seu tio.
l0b0 8/16
@ l0b0 Bob é meu tio. : D
cat