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.