Comment trouvez-vous le numéro de ligne dans Bash où une erreur s'est produite?
Je crée le script simple suivant avec des numéros de ligne pour expliquer ce dont nous avons besoin. Le script copiera les fichiers de
cp $file1 $file2
cp $file3 $file4
Lorsque l'une des commandes cp
échoue, la fonction se termine avec exit 1. Nous voulons ajouter la possibilité à la fonction d'imprimer également l'erreur avec le numéro de ligne (par exemple, 8 ou 12).
Est-ce possible?
1 #!/bin/bash
2
3
4 function in_case_fail {
5 [[ $1 -ne 0 ]] && echo "fail on $2" && exit 1
6 }
7
8 cp $file1 $file2
9 in_case_fail $? "cp $file1 $file2"
10
11
12 cp $file3 $file4
13 in_case_fail $? "cp $file3 $file4"
14
Plutôt que d'utiliser votre fonction, j'utiliserais plutôt cette méthode:
$ cat yael.bash
#!/bin/bash
set -eE -o functrace
file1=f1
file2=f2
file3=f3
file4=f4
failure() {
local lineno=$1
local msg=$2
echo "Failed at $lineno: $msg"
}
trap 'failure ${LINENO} "$BASH_COMMAND"' ERR
cp -- "$file1" "$file2"
cp -- "$file3" "$file4"
Cela fonctionne en interceptant ERR puis en appelant la fonction failure()
avec la ligne numéro actuelle + la commande bash qui a été exécutée.
Ici, je n'ai pas pris soin de créer les fichiers, f1
, f2
, f3
Ou f4
. Lorsque j'exécute le script ci-dessus:
$ ./yael.bash
cp: cannot stat ‘f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"
Il échoue, signalant le numéro de ligne plus la commande qui a été exécutée.
En plus de LINENO
contenant le numéro de ligne actuel, il y a BASH_LINENO
et FUNCNAME
(et BASH_SOURCE
) tableaux contenant les noms de fonction et les numéros de ligne à partir desquels ils sont appelés.
Vous pouvez donc faire quelque chose comme ceci:
#!/bin/bash
error() {
printf "'%s' failed with exit code %d in function '%s' at line %d.\n" "${1-something}" "$?" "${FUNCNAME[1]}" "${BASH_LINENO[0]}"
}
foo() {
( exit 0 ) || error "this thing"
( exit 123 ) || error "that thing"
}
foo
Courir qui imprimerait
'that thing' failed with exit code 123 in function 'foo' at line 9.
Si tu utilises set -e
, ou trap ... ERR
pour détecter automatiquement les erreurs, notez qu'elles comportent des mises en garde. Il est également plus difficile d'inclure une description de ce que le script faisait à l'époque (comme vous l'avez fait dans votre exemple), bien que cela puisse être plus utile pour un utilisateur normal que le simple numéro de ligne.
Voir par exemple ceux-ci pour les problèmes avec set -e
et d'autres:
Bash a une variable intégrée $LINENO
qui est remplacé par le numéro de ligne actuel dans une instruction, vous pouvez donc
in_case_fail $? "at $LINENO: cp $file1 $file2"
Vous pouvez également essayer d'utiliser trap ... ERR
qui s'exécute lorsqu'une commande échoue (si le résultat n'est pas testé). Par exemple:
trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR
Ensuite, si une commande comme cp $file1 $file2
échoue, vous obtiendrez le message d'erreur avec le numéro de ligne et une sortie. Vous trouverez également la commande en erreur dans la variable $BASH_COMMAND
(mais pas de redirections, etc.).