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?


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.


É 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.


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
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.