Como usar a instrução case para lidar com vários valores de retorno

1

Veja estas tentativas:

$ case 'true' in 0) echo success ;; *) echo fail ;; esac
fail
$ if 'true' ; then
> echo "success"
> else 
> echo "fail"
> fi
success

Agora, por que a declaração do caso está falhando? Você pode se perguntar por que eu não uso apenas a declaração if e vou explicar. Meu comando se complexo e pode retornar diferentes códigos de retorno em que eu quero agir. Eu não quero executar o comando várias vezes e não posso fazer:

my_command
res = $?
case $? in
...
esac

Isso porque eu uso set -e no meu script e, portanto, se my_command retornar falha, o script será cancelado.

Mas eu tenho uma solução alternativa ...

set +e
my_command
res=$?
set -e
case $? in 
...
esac

Mas isso é feio, então voltando à minha pergunta inicial ... por que posso usar apenas a versão case my_command in ... esac ?

    
por Paulo Matos 19.01.2017 / 20:26

4 respostas

5

Você não pode usar

case somecommand in ...

porque:

case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac 

Observe word , ou seja, uma string.

Usar $(true) não funciona, pois true não produz saída na saída padrão.

Eu sugeriria:

{ somecommand; err="$?"; } || true

case "$err" in ...

Isso interromperá a execução do script em errexit ( -e ) da saída.

Do manual bash (da descrição de set -e ):

The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test following the if or elif reserved words, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted with !.

    
por 19.01.2017 / 20:41
5

A sintaxe

'command'

significa substituir a saída padrão do comando pela linha de comando original. A saída não é a mesma coisa que o status de saída. O comando true não produz saída, então seu comando é equivalente a:

case "" in
0) echo success ;;
*) echo fail ;;
esac

Você pode resolver seu problema desta maneira:

case 'my_command; echo $?' in 
...
esac

BTW, no comando if você não precisa dos backticks, deve ser apenas:

if true
then echo successs
else echo fail
fi
    
por 19.01.2017 / 20:40
1

Mesmo com set -e , você ainda pode fazer:

if my_command
then
    echo success
else
    res=$?
    case $res in
      …
    esac
fi

Editar: você também pode fazer

res=0
my_command || res=$?
case $res in
    …
esac
    
por 19.01.2017 / 21:20
0

A resposta óbvia: Não use set -e neste caso.

Se você realmente precisa, talvez precise fazer algo realmente feio como:

case "$(bash -c 'my_command; echo "$?"')" in
    0) echo success ;;
    1) echo fail ;;
    2) echo "unexpected failure" ;;
    17) echo "wtf is this" ;;
    *) echo "I never thought this would happen" ;;
esac

Mas a abordagem óbvia seria:

set +e
my_command
res="$?"
set -e
case "$res" in
    ...

Observe também que espaços não são permitidos ao redor do sinal de igual na atribuição de variável em qualquer shell.

    
por 20.01.2017 / 06:20