Último comando com falha no bash

Respostas:

6

Use fcpara obter a linha de comando anterior. É normalmente usado para editar a linha de comando anterior no seu editor favorito, mas também possui um modo de "lista":

last_command="$(fc -nl -1)"

janmoesen
fonte
isso infelizmente não funciona bem muito bem como eu esperava se houver grandes declarações de caso de uso ou funções em uso ... :( acabei usando callere as matrizes de bash BASH_LINENO, BASH_SOURCEe FUNCNAMEfazer uma espécie de rastreamento de pilha.
phyatt
6

Se o último comando foi executado sem argumentos, ele será salvo na $_variável Normalmente, ele contém o último argumento do comando anterior - portanto, se não houver argumentos, o valor de $_é o último comando em si.

Outra opção é aprender os detalhes do último comando em segundo plano . Como l0b0 escreveu, $!mantém seu PID - para que você possa analisar a saída de ps $!(possivelmente com opções de formatação adicionais para ps).

rozcietrzewiacz
fonte
2

Não, mas você pode obtê-lo durante a execução para armazenar outros comandos:

  • $0: Caminho do script atual do shell.
  • $FUNCNAME: "Nome da função atual."
  • "$@": Todos os parâmetros do comando atual, citados separadamente.
  • $!: "PID (ID do processo) do último trabalho executado em segundo plano."
  • $$: "ID do processo (PID) do próprio script."

O comando completo do script atual deve, portanto, ser "$0" "$@". Se é uma função, deveria ser "$FUNCNAME" "$@". Convém armazenar isso em uma matriz para processamento futuro. Por exemplo, armazene isso em test.sh:

#!/usr/bin/env bash
foo()
{
    declare -a command=("$0")
    for param in "$@"
    do
        command+=("$(printf %q "$param")")
    done
    echo "${command[@]}"
}
foo "$@"

Ao executar ./test.sh "first argument" "second argument", ele deve retornar:

./test.sh first\ argument second\ argument

Quais são chamadas equivalentes.

l0b0
fonte
No bash, há uma BASH_COMMANDvariável, mas não parece ser útil de nenhuma forma, além do uso em armadilhas.
enzotib
Obrigado pela sua contribuição. E se eu executar some-commandem um script de shell e ele falhar. Vou ter um status diferente de zero $?, "não" ainda será válido pela existência de retenção de variável some-command?
Eimantas
Até onde eu sei, o único fato de um comando falhar não altera o conjunto de informações que seu shell armazena sobre ele. Então eu diria que sim, "não" .
#
2

A DEBUGarmadilha permite que você execute um comando antes de qualquer execução simples. Uma versão em cadeia do comando a ser executado (com palavras separadas por espaços) está disponível na BASH_COMMANDvariável

trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG

echo "last command is $previous_command"

Observe que previous_commandisso muda toda vez que você executa um comando, então salve-o em uma variável para usá-lo. Se você também deseja conhecer o status de retorno do comando anterior, salve os dois em um único comando.

cmd=$previous_command ret=$?
if [ $ret -ne 0 ]; then echo "$cmd failed with error code $ret"; fi

Se você deseja abortar apenas os comandos com falha, use set -epara fazer o script sair no primeiro comando com falha. Você pode exibir o último comando da EXITarmadilha .

set -e
trap 'echo "exit $? due to $previous_command"' EXIT

Uma abordagem alternativa que pode funcionar para alguns usos é usar set -xpara imprimir um rastreamento da execução do script e examinar as últimas linhas do rastreamento.

Gilles 'SO- parar de ser mau'
fonte
0

Eu acho essencial encontrar o último comando com falha ao ter set -ee set -o pipefailopções, caso contrário, o bash simplesmente é interrompido sem comentários sobre o porquê, então foi o que eu achei funcionando bem:

#!/usr/bin/env bash
set -eu
set -o pipefail

cur_command=
first_err_command=
first_err_lineno=
# This trap is executed in exactly the same conditions in which the `set -e` results in an exit.
trap 'cur_command=$BASH_COMMAND;
      if [[ -z "$first_err_command" ]]; then
          first_err_command=$cur_command;
          first_err_lineno=$LINENO;
      fi' ERR
trap 'if [[ ! -z "$first_err_command" ]]; then
          echo "ERROR: Aborting at line: $first_err_lineno on command: $first_err_command";
      fi' EXIT

echo "The following command causes bash to abort, but it should also result in a nice message"
false
echo "This message is not expected"

Se você executar o procedimento acima, você verá o tipo de saída abaixo:

The following command causes bash to abort, but it should also result in a nice message
ERROR: Aborting at line: 22 on command: false

O número da linha nem sempre é preciso, mas deve fornecer algo próximo o suficiente para ser útil.

haridsv
fonte