web-dev-qa-db-fra.com

Piège, err et écho à la ligne d'erreur

J'essaie de créer des rapports d'erreur à l'aide d'un piège pour appeler une fonction sur toutes les erreurs:

Trap "_func" ERR

Est-il possible d'obtenir quelle ligne le signal ERR a été envoyé? La coquille est bash.

Si je le fais, je peux lire et signaler quelle commande a été utilisée et connectez-vous/effectuer certaines actions.

Ou peut-être que je vais tout cela mal?

J'ai testé avec ce qui suit:

#!/bin/bash
trap "ECHO $LINENO" ERR

echo hello | grep "asdf"

Et $LINENO retourne 2. ne fonctionne pas.

32
Mechaflash

Comme indiqué dans des commentaires, votre citation est fausse. Vous avez besoin de guillemets simples pour prévenir $LINENO D'être étendu lorsque la ligne de piège est d'abord analysée.

Cela marche:

#! /bin/bash

err_report() {
    echo "Error on line $1"
}

trap 'err_report $LINENO' ERR

echo hello | grep foo  # This is line number 9

Le courir:

 $ ./test.sh
 Error on line 9
66
Mat

Vous pouvez également utiliser l'appelant Bash Bashetin ':

#!/bin/bash

err_report() {
  echo "errexit on line $(caller)" >&2
}

trap err_report ERR

echo hello | grep foo

il imprime aussi le nom du fichier:

$ ./test.sh
errexit on line 9 ./test.sh
17
Andrew Ivanov

J'aime vraiment la réponse donnée par @mat ci-dessus. Construire sur ceci, j'ai écrit un petit assistant qui donne un peu plus de contexte pour l'erreur:

Nous pouvons inspecter le script pour la ligne qui a provoqué l'échec:

err() {
    echo "Error occurred:"
    awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$0 }' L=$1 $0
}
trap 'err $LINENO' ERR

Ici, c'est dans un petit script de test:

#!/bin/bash

set -e

err() {
    echo "Error occurred:"
    awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$0 }' L=$1 $0
}
trap 'err $LINENO' ERR

echo one
echo two
echo three
echo four
false
echo five
echo six
echo seven
echo eight

Quand nous l'exécutons, nous obtenons:

$ /tmp/test.sh
one
two
three
four
Error occurred:
12      echo two
13      echo three
14      echo four
15   >>>false
16      echo five
17      echo six
18      echo seven
8
unpythonic

Voici une autre version, inspirée de @sanmai et @unpythonic. Il affiche des lignes de script autour de l'erreur, avec des numéros de ligne et l'état de sortie - à l'aide de la queue et de la tête, ce qui semble plus simple que la solution AWK.

Affichage de cela comme deux lignes ici pour la lisibilité - vous pouvez rejoindre ces lignes en une seule si vous préférez (préserver le ;):

trap 'echo >&2 "Error - exited with status $? at line $LINENO:"; 
         pr -tn $0 | tail -n+$((LINENO - 3)) | head -n7' ERR

Cela fonctionne assez bien avec set -euo pipefail ( Mode strict non officiel ) - Toute erreur de variable non définie donne un numéro de ligne sans tirer le pseudo-signal ERR, mais les autres cas présentent le contexte.

Exemple de sortie:

myscript.sh: line 27: blah: command not found
Error - exited with status 127 at line 27:
   24   # Do something
   25   lines=$(wc -l /etc/passwd)
   26   # More stuff
   27   blah
   28   
   29   # Check time
   30   time=$(date)
1
RichVel