Log do código de saída do comando, semelhante ao comando time

8

usando

time sleep 1

rendimentos:

$ time sleep 1

real    0m1.005s
user    0m0.001s
sys     0m0.001s

existe um comando que eu possa usar para imprimir o código de saída de sleep ou qualquer outro comando que eu queira executar?

Algo gosta:

$ log-exit-code sleep 1

talvez isso seja suficiente?

sleep 1 && echo "$?"
    
por Alexander Mills 07.09.2017 / 21:46

7 respostas

4

Nos meus testes até agora, isso funcionou:

command && echo "$?" || echo "$?"

Apenas diz para ecoar o código de saída, se for bem-sucedido ou se falhar.

Como Sato apontou abaixo, isso é essencialmente o mesmo que:

command; echo "$?"

Uma coisa que poderia fazer o comando e / ou valer a pena é algo como:

command && echo "Success! Exit Code: $?" || echo "Failure! Exit Code: $?"

Se você precisar que seu script atue no código de saída, como é a preocupação de Olivier, não é um problema. Seu script pode ser parecido com:

command
case "$?" in; 
    0) echo "Command exited with: 0"
       <command if good>
       ;;
    1) echo "Command exited with: 1"
        <command if bad>
        ;;
    255) echo "Command exited with: 255"  # for ssh maybe?
         <command if 255>
         ;;
    *) echo "Command exited with: >2"
        <command for other exit code>
        ;;
esac
    
por 07.09.2017 / 22:23
11

cmd && echo "$?" não funcionaria, pois seria necessário imprimir apenas zeros (o echo seria executado apenas com a conclusão bem-sucedida do comando anterior).

Aqui está uma pequena função de shell para você:

tellexit () {
    "$@"

    local err="$?"
    printf 'exit code\t%d\n' "$err" >/dev/tty
    return "$err"
}

Isso imprime o código de saída do comando determinado de maneira semelhante ao comando time .

$ tellexit echo "hello world"
hello world
exit code       0

$ tellexit false
exit code       1

Ao redirecionar o printf para /dev/tty na função, ainda poderemos usar tellexit com redirecionamentos sem incluir lixo em nossos fluxos de saída ou de erro padrão:

$ tellexit bash -c 'echo hello; echo world >&2' >out 2>err
exit code       0
$ cat out
hello
$ cat err
world

Ao salvar o código de saída em uma variável, podemos devolvê-lo ao chamador:

$ tellexit false || echo 'failed'
exit code       1
failed

Uma versão mais sofisticada da mesma função também imprime o sinal que matou o comando se o código de saída for maior que 128 (o que significa que terminou devido a um sinal):

tellexit () {
    "$@"

    local err="$?"

    if [ "$err" -gt 128 ]; then
        printf 'exit code\t%d (%s)\n' "$err" "$(kill -l "$err")" >/dev/tty
    else
        printf 'exit code\t%d\n' "$err" >/dev/tty
    fi

    return "$err"
}

Teste:

$ tellexit sh -c 'kill $$'
exit code       143 (TERM)

$ tellexit sh -c 'kill -9 $$'
Killed
exit code       137 (KILL)

(A coisa local requer ash / pdksh / bash / zsh , ou você pode alterá-la para typeset , o que algumas outras shells também entendem.)

    
por 07.09.2017 / 21:58
7

Use uma função de invólucro de shell. Provavelmente com um nome diferente.

$ exito() { "$@"; echo $?; }
$ exito true
0
$ exito false
1
$ exito echo "test test"      
test test
0
$ 

(Isto, é claro, corromperá a saída padrão, então use o tty como mostrado por @Kusalananda ou não o use fora de contextos interativos.)

Desviando para um território não-portável, algumas camadas podem relatar o status de todos os comandos em um pipeline, não apenas o último, por exemplo, no ZSH se você quiser que as falhas sejam relatadas em um pipeline inteiro:

% TRAPZERR() { print >/dev/tty $pipestatus }
% perl -e 'exit 42' | perl -e 'exit 99'
42 99
% false | perl -e 'exit 42' | perl -e 'exit 99'
1 42 99
% perl -e 'exit 42' | perl -e 'exit 99' | true
% 

TRAPZERR caso contrário, não será disparado quando não houver erro (no cabeçalho "não há notícias boas").

    
por 07.09.2017 / 21:58
5

O GNU time tem uma opção para isso:

time -f %x sleep 1
0

Passa pelo código de saída 1 , a menos que seja morto por um sinal 2 :

$ /usr/bin/time -f %x sleep 1; echo $?
0
0

$ /usr/bin/time -f %x sleep 2x; echo $?
sleep: invalid time interval ‘2x’
Try 'sleep --help' for more information.
1
1

$ /usr/bin/time -f %x sleep 60s; echo $? # Press ^C before a minute elapses
0
2

Se você quiser saber / manipular a situação de kill do sinal, passe -v e grep o stderr para a string Command terminated by signal .

1 Obrigado a Olivier Dulac por notar que o código de saída passa.
2 Além disso, obrigado Stéphane Chazelas por apontar que o código de saída do sinal de matar não passa através de.

    
por 08.09.2017 / 05:52
2

Para ser um pouco mais robusto, envie o status de saída para um FD separado para que ele possa ser tratado independentemente do stdout / stderr:

exit_status() {
    "$@"
    rv=$?
    echo >&3 "$rv"
    return "$rv"
}

# exit status and stdout to stdout:
> exit_status echo "hello" 3>&1
hello
0

# exit_status to stdout, stdout to /dev/null
> exit_status echo "hello" 3>&1 1>/dev/null
0
> exit_status ehco "hello" 3>&1 1>/dev/null
ehco: command not found
127

# exit_status to stdout, stdout and stderr to /dev/null
> exit_status ehco "hello" 3>&1 &>/dev/null
127

Note que você precisará fazer algo com o FD3 ou ele dirá Bad file descriptor .

Isso pode ser configurado ainda mais para fornecer essas saídas para entradas de outro programa fazendo com que o outro programa ouça em mais de um FD; você poderia usar isso como uma espécie de Kibana dos anos 90:)

    
por 08.09.2017 / 05:24
1

Eu não gosto de todas as outras respostas (embora eu goste muito de sua esperteza): elas exibem o código de saída, mas elas também MUDAM. (a parte de exibição é verdadeira, portanto, depois disso, o código de retorno é 0)

Aqui está uma versão modificada:

do_and_tell () {
   "$@"
   returncode="$?"
   printf "Execution of : \n%s\n yelded a return code of: \n%s\n" "$*" "$returncode"
   return $returncode  # the interresting addition... keeps the commands return value.
}

## usage:

prompt$ do_and_tell true
Execution of : 
true
 yelded a return code of: 
0

prompt$ echo $?
0

prompt$ do_and_tell false
Execution of : 
false
 yelded a return code of: 
1

prompt$ echo $?
1
    
por 08.09.2017 / 13:17
1

Enquanto todas as outras respostas (muito interessantes) abordam a questão exata que o OP fez, na prática, as coisas geralmente são mais simples. Basta salvar o status de saída para uma variável (imediatamente após o comando) e relatar ou registrá-lo da maneira que desejar. Por exemplo. imprima para / dev / stderr ou escreva / acrescente-o como uma mensagem de texto em um arquivo de log. E também é preservado para uso na tomada de decisão / controle de fluxo no código subsequente.

Se estiver em uma função:

function some-function () {
    local rc ## to avoid side effects
    ...
    some-command ## run any command
    rc=$?  ## save the return status in a variable
    echo "some-command returned $rc" ## optionally tell the user about it
    ...
    return $rc  ## at the end, if appropriate
}

Se estiver diretamente em um script:

some-command ## run any command
rc=$?  ## save the return status in a variable
echo "some-command returned $rc" ## optionally tell the user about it
...
exit $rc    ## at the end to tell any calling script about it, if appropriate

(Ducking e cobrindo porque isso não responde a pergunta exata .)

    
por 09.09.2017 / 12:11