Comment afficher le numéro de ligne lors de l'exécution du script bash

89

J'ai un script de test qui a beaucoup de commandes et générera beaucoup de sortie, j'utilise set -xou set -vet set -e, donc le script s'arrêterait en cas d'erreur. Cependant, il est encore assez difficile pour moi de localiser la ligne sur laquelle l'exécution s'est arrêtée afin de localiser le problème. Existe-t-il une méthode qui peut afficher le numéro de ligne du script avant que chaque ligne ne soit exécutée? Ou afficher le numéro de ligne avant l'exposition de commande générée par set -x? Ou toute méthode qui peut résoudre mon problème d'emplacement de ligne de script serait d'une grande aide. Merci.

dspjm
la source

Réponses:

159

Vous mentionnez que vous utilisez déjà -x. La variable PS4indique que la valeur est l'invite imprimée avant que la ligne de commande ne soit renvoyée lorsque l' -xoption est définie et que la valeur par défaut est :suivie d'un espace.

Vous pouvez changer PS4pour émettre le LINENO(Le numéro de ligne dans le script ou la fonction shell en cours d'exécution).

Par exemple, si votre script lit:

$ cat script
foo=10
echo ${foo}
echo $((2 + 2))

L'exécuter ainsi imprimerait les numéros de ligne:

$ PS4='Line ${LINENO}: ' bash -x script
Line 1: foo=10
Line 2: echo 10
10
Line 3: echo 4
4

http://wiki.bash-hackers.org/scripting/debuggingtips donne l'ultime PS4qui produirait tout ce dont vous aurez éventuellement besoin pour le traçage:

export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
devnull
la source
4
Je me demande pourquoi personne ne mentionne cela pour "Comment déboguer les scripts shell?" . C'est bien mieux que justeecho
Suvarna Pattayil
@VusP D'accord, il vaut echomieux éviter les déclarations inutiles .
devnull
2
Je ne peux pas m'empêcher de penser que cela -x devrait imprimer les numéros de ligne. Ou, peut-être - nx devrait inclure les numéros de ligne. Pour moi, c'est un de ces moments "WTF" ...
jww
1
Mec, j'aurais aimé être au courant de cette concoction PS4 plus tôt ... Cela m'aurait sauvé tant de maux de tête
Niken
2
\033[0;33m+(${BASH_SOURCE}:${LINENO}):\033[0m ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'pour quelques couleurs
Ulysse BN
34

Dans Bash, $LINENOcontient le numéro de ligne où le script est en cours d'exécution.

Si vous avez besoin de connaître le numéro de ligne où la fonction a été appelée, essayez $BASH_LINENO. Notez que cette variable est un tableau.

Par exemple:

#!/bin/bash       

function log() {
    echo "LINENO: ${LINENO}"
    echo "BASH_LINENO: ${BASH_LINENO[*]}"
}

function foo() {
    log "$@"
}

foo "$@"

Voir ici pour plus de détails sur les variables Bash.

Deqing
la source
0

Solution simple (mais puissante): placez echoautour du code que vous pensez qui cause le problème et déplacez la echoligne par ligne jusqu'à ce que les messages n'apparaissent plus à l'écran - car le script s'est arrêté à cause d'une erreur avant.

Solution encore plus puissante: installez bashdble débogueur bash et déboguez le script ligne par ligne

hek2mgl
la source
2
echoLes trucs autour peuvent aider dans de nombreux cas, mais échouent lorsque vous essayez de l'appliquer dans des fonctions qui ont une sortie significative et analysable.
Eliran Malka
1
@EliranMalka Fair point. Vous pouvez faire écho à stderr dans ce cas:echo "foo" >&2
hek2mgl
1
... il faut faire écho à stderr dans tous les cas où le but est de messages de nature diagnostique.
Charles Duffy le
0

Solution de contournement pour les coques sans LINENO

Dans un script assez sophistiqué, je n'aimerais pas voir tous les numéros de ligne; plutôt je voudrais être en contrôle de la sortie.

Définir une fonction

echo_line_no () {
    grep -n "$1" $0 |  sed "s/echo_line_no//" 
    # grep the line(s) containing input $1 with line numbers
    # replace the function name with nothing 
} # echo_line_no

Utilisez-le avec des citations comme

echo_line_no "this is a simple comment with a line number"

La sortie est

16   "this is a simple comment with a line number"

si le numéro de cette ligne dans le fichier source est 16.

Cela répond essentiellement à la question Comment afficher le numéro de ligne lors de l'exécution d'un script bash pour les utilisateurs de ash ou d'autres shells sans LINENO.

Quelque chose à ajouter?

Sûr. Pourquoi en avez-vous besoin? Comment travaillez-vous avec cela? Que pouvez-vous faire avec ça? Cette approche simple est-elle vraiment suffisante ou utile? Pourquoi voulez-vous bricoler ça?

Veut en savoir plus? Lire les réflexions sur le débogage

kklepper
la source