Dernière commande échouée dans bash


Réponses:


6

Utilisez fcpour obtenir la ligne de commande précédente. Il est normalement utilisé pour éditer la ligne de commande précédente dans votre éditeur préféré, mais il a aussi un mode "liste":

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


malheureusement cela ne fonctionne pas tout à fait comme je m'y attendais s'il y a de grandes déclarations de cas en cours d' utilisation ou fonctions en cours d' utilisation ... :( J'ai fini à l' aide calleret les tableaux de bash BASH_LINENO, BASH_SOURCEet FUNCNAMEde faire une sorte de trace de la pile.
phyatt

6

Si la dernière commande a été exécutée sans arguments, elle sera enregistrée dans la $_variable. Il contient normalement le dernier argument de la commande précédente - donc s'il n'y avait pas d'arguments, la valeur de $_est la dernière commande elle-même.

Une autre option consiste à connaître les détails de la dernière commande d' arrière-plan . Comme l'a écrit l0b0, $!contient son PID - vous pouvez donc analyser la sortie de ps $!(éventuellement avec des options de formatage supplémentaires pour ps).


2

Non, mais vous pouvez l'obtenir lors de l'exécution pour le stocker pour d'autres commandes:

  • $0: Chemin du script shell actuel.
  • $FUNCNAME: "Nom de la fonction actuelle."
  • "$@": Tous les paramètres de la commande en cours, cités séparément.
  • $!: "PID (ID de processus) du dernier travail exécuté en arrière-plan."
  • $$: "ID de processus (PID) du script lui-même."

La commande complète du script actuel devrait donc être "$0" "$@". Si c'est une fonction, ça devrait l'être "$FUNCNAME" "$@". Vous souhaiterez peut-être le stocker dans un tableau pour un traitement ultérieur. Par exemple, stockez-le dans test.sh:

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

Lors de l'exécution ./test.sh "first argument" "second argument", il devrait retourner:

./test.sh first\ argument second\ argument

Ce sont des appels équivalents.


Dans bash, il y a une BASH_COMMANDvariable, mais ne semble d'aucune façon utile, à part l'utilisation dans les pièges.
enzotib

Merci pour votre contribution. Et si j'exécute some-commandun script shell et qu'il échoue. Je vais avoir un statut différent de zéro $?, est-ce que "non" restera valable pour l'existence d'une détention variable some-command?
Eimantas

Pour autant que je sache, le seul fait qu'une commande ait échoué ne change pas l'ensemble des informations que votre shell stocke à ce sujet. Je dirais donc oui, "non" .
rozcietrzewiacz

2

Le DEBUGpiège vous permet d'exécuter une commande juste avant toute exécution de commande simple. Une version chaîne de la commande à exécuter (avec des mots séparés par des espaces) est disponible dans la BASH_COMMANDvariable.

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

echo "last command is $previous_command"

Notez que previous_commandcela changera à chaque fois que vous exécutez une commande, alors enregistrez-la dans une variable afin de l'utiliser. Si vous souhaitez également connaître l'état de retour de la commande précédente, enregistrez les deux dans une seule commande.

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

Si vous ne souhaitez interrompre qu'une commande ayant échoué, utilisez set -epour faire quitter votre script à la première commande ayant échoué. Vous pouvez afficher la dernière commande du EXITpiège .

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

Une autre approche qui pourrait fonctionner pour certaines utilisations consiste à set -ximprimer une trace de l'exécution du script et à examiner les dernières lignes de la trace.


0

Je trouve qu'il est essentiel de trouver la dernière commande ayant échoué lors de l'utilisation des options set -eet set -o pipefail, car sinon bash abandonne simplement sans aucun retour sur pourquoi, c'est donc ce que j'ai trouvé fonctionnant 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 vous exécutez ce qui précède, vous finirez par voir le type de sortie ci-dessous:

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

Le numéro de ligne n'est peut-être pas toujours précis, mais il devrait vous donner quelque chose d'assez proche pour être utile.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.