Como manter o último status de saída após o teste

8

É possível manter o status de saída do último comando ( $? ) inalterado após um teste?

Por exemplo, eu gostaria de fazer:

command -p sudo ...
[ $? -ne 1 ] && exit $?

O último exit $? deve retornar o status de saída do sudo, mas sempre retorna 0 (o código de saída do teste).

É possível fazer isso sem uma variável temporária?

Outro exemplo para esclarecer:

 spd-say "$@"
 [ $? -ne 127 ] && exit $?

Neste caso, quero sair apenas se o primeiro comando for encontrado (código de saída! = 127 ). E eu quero sair com o código de saída real spd-say (pode não ser 0 ).

EDITAR: Esqueci de mencionar que prefiro uma solução de reclamação POSIX para melhor portabilidade.

Eu uso essa construção em scripts onde eu quero fornecer alternativas para o mesmo comando. Por exemplo, veja meu script crc32 .

O problema com variáveis temporárias é que elas podem sombrear outras variáveis e evitar que você precise usar nomes longos, o que não é bom para a legibilidade do código.

    
por eadmaster 13.06.2015 / 15:35

6 respostas

3

$_ funcionará em (pelo menos) interativo dash , bash , zsh , ksh (embora aparentemente não em uma declaração condicional conforme solicitado) e mksh shells. Desses - que eu saiba - somente bash e zsh também o preencherão em um shell com script. Não é um parâmetro POSIX - mas é bastante portátil para qualquer shell moderno e interativo.

Para uma solução mais portátil, você pode fazer:

command -p sudo ...
eval '[ "$?" = 127 ] || exit '"$?"

O que basicamente permite expandir o valor inicial de $? para o final do script antes mesmo de testar seu valor.

Mas de qualquer forma, desde que você pareça estar testando se o comando sudo pode ou não ser encontrado na string de -p caminho portátil do shell com command , eu acho que você poderia ir um pouco mais diretamente. Além disso, só para ficar claro, command não irá testar a localização de quaisquer argumentos para sudo - então é apenas sudo - e nada invoca - o que é relevante para esse valor de retorno.

E mesmo assim, se é isso que você está tentando fazer:

command -pv sudo >/dev/null || handle_it
command -p  sudo something or another

... funcionaria muito bem como um teste sem qualquer chance de erros no comando sudo runs retornando de tal forma que poderia distorcer os resultados do seu teste.

    
por 14.06.2015 / 03:03
8

Existem várias opções para lidar com o status de saída de forma confiável, sem sobrecarga, dependendo dos requisitos reais.

Você pode salvar o status de saída usando uma variável:

command -p sudo ...
rc=$?
[ "$rc" -ne 1 ] && echo "$rc"

Você pode verificar diretamente o sucesso ou o fracasso:

if  command -p sudo ...
then  echo success
else  echo failure
fi

Ou use uma construção case para diferenciar o status de saída:

command -p sudo ...
case $? in
(1) ... ;;
(127) ... ;;
(*) echo $? ;;
esac

com o caso especial perguntado na pergunta:

command -p sudo ...
case $? in (1) :;; (*) echo $?;; esac

Todas essas opções têm a vantagem de estarem em conformidade com o padrão POSIX.

(Nota: para ilustração, usei os comandos echo acima; substitua as instruções exit apropriadas para corresponder à função solicitada.)

    
por 13.06.2015 / 16:33
7
command -p ...
test 1 -ne $? && exit $_

Use $_ , que se expande para o último argumento do comando anterior.

    
por 13.06.2015 / 16:34
6

Você pode definir (e usar) uma função de shell:

check_exit_status()
{
    [ "$1" -ne 1 ] && exit "$1"
}

Então

command -p sudo ...
check_exit_status "$?"

Indiscutivelmente, isso é "trapaça" já que faz uma cópia de $? na lista de argumentos check_exit_status .

Isso pode parecer um pouco estranho, e é. (Isso às vezes acontece quando você impõe restrições arbitrárias aos problemas.) Isso pode parecer inflexível, mas não é. Você pode tornar check_exit_status mais complexo, adicionando argumentos que informam que teste (s) fazer no valor do status de saída.

    
por 13.06.2015 / 17:21
0

Para responder à sua pergunta direta, não, não é possível manter $? inalterado. E este é um daqueles casos em que suspeito que você está se concentrando no problema errado. Uma variável temporária é a maneira padrão e preferida de obter o efeito que você está procurando. É tão normal que eu sugiro abandonar (ou repensar) qualquer que seja a razão que você acha que tem para não querer usar um; Eu duvido que valha a complexidade extra adicionada por qualquer outro método.

Se você está apenas pedindo por simples curiosidade, então a resposta é não.

    
por 14.06.2015 / 02:48
0

Este é o meu snippet de código para manter um status de saída anterior sem sair do script / shell atual

EXIT_STATUS=1
if [[ $EXIT_STATUS == 0 ]]
then
  echo yes
else
  (exit $EXIT_STATUS)
fi
    
por 22.07.2017 / 08:44