Último comando fallido en bash

Respuestas:

6

Use fcpara obtener la línea de comando anterior. Normalmente se usa para editar la línea de comando anterior en su editor favorito, pero también tiene un modo de "lista":

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

janmoesen
fuente
esta desgracia no funciona bien muy bien cómo me esperaba si hay declaraciones de casos grandes en uso o funciones en uso ... :( Terminé usando callery las matrices de bash BASH_LINENO, BASH_SOURCEy FUNCNAMEhacer una especie de seguimiento de la pila.
phyatt
6

Si el último comando se ejecutó sin argumentos, se guardará en la $_variable. Esto normalmente contiene el último argumento del comando anterior, por lo que si no hubiera argumentos, el valor de $_es el último comando en sí.

Otra opción es aprender los detalles del último comando de fondo . Como escribió l0b0, $!contiene su PID, por lo que puede analizar la salida de ps $!(posiblemente con opciones de formato adicionales ps).

rozcietrzewiacz
fuente
2

No, pero puede obtenerlo durante la ejecución para almacenar otros comandos:

  • $0: Ruta del script de shell actual.
  • $FUNCNAME: "Nombre de la función actual".
  • "$@": Todos los parámetros del comando actual, citados por separado.
  • $!: "PID (ID de proceso) del último trabajo ejecutado en segundo plano".
  • $$: "ID de proceso (PID) del script en sí".

Por lo tanto, el comando completo del script actual debería ser "$0" "$@". Si es una función, debería ser "$FUNCNAME" "$@". Es posible que desee almacenar eso en una matriz para su procesamiento futuro. Por ejemplo, almacene esto en test.sh:

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

Cuando se ejecuta ./test.sh "first argument" "second argument", debería devolver:

./test.sh first\ argument second\ argument

Que son llamadas equivalentes.

l0b0
fuente
En bash hay una BASH_COMMANDvariable, pero no parece ser útil de ninguna manera, aparte del uso en trampas.
enzotib
Gracias por tu contribución. ¿Qué pasa si ejecuto some-commandun script de shell y falla? Tendré un estado distinto de cero $?, ¿"no" se mantendrá por la existencia de retención variable some-command?
Eimantas
Hasta donde sé, el solo hecho de que un comando haya fallado no cambia el conjunto de información que su shell almacena al respecto. Entonces diría que sí, "no" .
rozcietrzewiacz
2

La DEBUGtrampa le permite ejecutar un comando justo antes de la ejecución de cualquier comando simple. Una versión de cadena del comando a ejecutar (con palabras separadas por espacios) está disponible en la BASH_COMMANDvariable.

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

echo "last command is $previous_command"

Tenga en cuenta que previous_commandcambiará cada vez que ejecute un comando, así que guárdelo en una variable para poder usarlo. Si desea conocer también el estado de retorno del comando anterior, guarde ambos en un solo comando.

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

Si solo desea abortar en un comando fallido, use set -epara que su script salga en el primer comando fallido. Puede mostrar el último comando de la EXITtrampa .

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

Un enfoque alternativo que podría funcionar para algunos usos es utilizar set -xpara imprimir un seguimiento de la ejecución del script y examinar las últimas líneas del seguimiento.

Gilles 'SO- deja de ser malvado'
fuente
0

Creo que es esencial encontrar el último comando fallido cuando tengo set -ey set -o pipefailopciones, ya que de lo contrario bash simplemente aborta sin comentarios sobre por qué, así que esto es lo que encontré funcionando bien:

#!/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"

Si ejecuta lo anterior, terminará viendo el siguiente tipo de salida a continuación:

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

Es posible que el número de línea no siempre sea exacto, pero debería darle algo lo suficientemente cercano como para ser útil.

haridsv
fuente