/ bin / sh retorna 0 quando não encontrou um comando em uma instrução if, é o esperado?

0

Eu escrevi um cão de guarda C ++ que executa um conjunto de scripts para determinar se há um problema no sistema.

O código é um pouco peludo por isso não vou mostrá-lo aqui, mas é equivalente a uma chamada de sistema como a seguir:

int const r(system("/bin/sh /path/to/script/test-health"));

Apenas, r é 0 quando o script falha porque um comando está faltando em uma instrução if . Há o bit ofensivo do script:

set -e
[...]
if unknown_command arg1 arg2
then
[...]

O unknown_command obviamente falha desde ... é desconhecido. Nesse ponto, o script termina porque tenho o set -e no início.

O código de saída, no entanto, será 0 nessa situação.

Haveria uma maneira de eu obter um código de saída de 1 em tal situação?

i.e. A questão é detectar o erro sem ter que adicionar um teste para saber se o unknown_command existe. Eu sei como fazer isso:

if ! test -x unknown_command
then
    exit 1
fi

O meu ponto é que, quando eu escrever esse roteiro, espero unknown_command de existir como eu instalá-lo eu mesmo, mas se algo der cópias erradas ou alguém o script em outro sistema sem instalar tudo, eu gostaria de saber que Eu recebi um erro ao executar o script.

    
por Alexis Wilke 10.02.2018 / 04:40

4 respostas

5

Do padrão POSIX, sobre set -e :

The -e setting shall be ignored when executing the compound list following the while, until, if, or elif reserved word, a pipeline beginning with the ! reserved word, or any command of an AND-OR list other than the last.

Isso significa que a execução de um comando desconhecido em uma instrução if não fará com que o script termine quando estiver sendo executado em set -e . Ou melhor, set -e não fará com que termine.

Usuário command -v para testar se existe um utilitário no atual PATH , a menos que você use caminhos completos para os utilitários que invoca e, nesse caso, um teste -x seria suficiente, como em sua pergunta.

Veja também: Por que não usar "which"? O que usar então?

    
por 10.02.2018 / 09:02
3

At that point the script ends because I have the set -e at the start.

Isto é uma falsidade.

Script comum:

$ cat ./weeble
set -e
if wobble ; then echo wobbled. ; else echo did not wobble. ; fi
echo did not fall down.
type wobble || exec false
exec true
$ 

Você diz que sabe como testar um comando desconhecido.

Almquist shell como /bin/sh :

$ /bin/sh ./weeble ; echo $?
./weeble: wobble: not found
did not wobble.
did not fall down.
wobble: not found
1
$ /bin/sh -e ./weeble ; echo $?
./weeble: wobble: not found
did not wobble.
did not fall down.
wobble: not found
1
$ 

Korn shell como /bin/sh :

$ /bin/sh ./weeble ; echo $?
./weeble[2]: wobble: not found
did not wobble.
did not fall down.
wobble not found
1
$ /bin/sh -e ./weeble ; echo $? 
./weeble[2]: wobble: not found
did not wobble.
did not fall down.
wobble not found
1
$ 

Shell Bourne Again como /bin/sh :

$ /bin/exec -a /bin/sh /usr/local/bin/bash ./weeble ; echo $?
./weeble: line 2: wobble: command not found
did not wobble.
did not fall down.
./weeble: line 4: type: wobble: not found
1
$ /bin/exec -a /bin/sh /usr/local/bin/bash -e ./weeble ; echo $?
./weeble: line 2: wobble: command not found
did not wobble.
did not fall down.
./weeble: line 4: type: wobble: not found
1
$ 

Z shell como /bin/sh :

$ /bin/exec -a /bin/sh /usr/local/bin/zsh ./weeble ; echo $?
./weeble:2: command not found: wobble
did not wobble.
did not fall down.
wobble not found
1
$ /bin/exec -a /bin/sh /usr/local/bin/zsh -e ./weeble ; echo $?
./weeble:2: command not found: wobble
did not wobble.
did not fall down.
wobble not found
1
$ 

Como sua pergunta pergunta como evitar algo que não acontece em primeiro lugar e assume uma falsidade como sua premissa e seu título, ela é incontestável.

    
por 10.02.2018 / 08:51
1

O if não sai porque o set -e foi configurado:

#!/bin/sh

set -e

if unknown_command; then
    echo "On true, exit code $?"
else
    echo "on false, exit code $?"
fi

echo "after if, exit code $?"

Imprime (em todos os shells testados, com variações da mensagem de erro):

sh            : … : unknown_command: not found                                    
on false, exit code 127                                                                                                          
after if, exit code 0 

Ambos com set -e definido ou não definido.

Se você quiser detectar comandos perdidos, capture um código de saída de 127 1 :

#!/bin/sh

if unknown_command; then
    echo "On true, exit code $?"
else
    ec=$?
    if [ "$ec" = '127' ]; then
        echo "the command failed because it does not exist"
        exit 127
    fi
    echo "on false, exit code $ec"
fi

echo "after if, exit code $?"

Qual será executado assim:

$ ./script
./script: 5: ./script: unknown_command: not found
the command failed because it does not exist

1
Sobre o código de saída 127

    
por 10.02.2018 / 21:35
0

Você deve fazer uma das duas coisas:

1:

unknown_command arg1 arg2
subsequent command(s)

Em seguida, o set -e fará com que o script termine se unknown_command falhar. Por que você está dizendo if ?

2:

if unknown_command arg1 arg2
then
    subsequent command(s)
              ︙
else
    issue error message(s)
    do any desired cleanup
    exit 1
fi
    
por 11.02.2018 / 05:44