Wie debugge ich ein Bash-Skript? [geschlossen]

159

Gibt es eine Möglichkeit, ein Bash-Skript zu debuggen? ZB etwas, das eine Art Ausführungsprotokoll druckt, wie "Anrufzeile 1", "Anrufleitung 2" usw.

Korvus
quelle
2
Hier gibt es eine ähnliche Frage: serverfault.com/questions/16204/…
Bis auf weiteres angehalten.

Antworten:

195
sh -x script [arg1 ...]
bash -x script [arg1 ...]

Diese geben Ihnen eine Spur von dem, was ausgeführt wird. (Siehe auch "Klarstellung" am Ende der Antwort.)

Manchmal müssen Sie das Debuggen innerhalb des Skripts steuern. In diesem Fall können Sie, wie Cheeto mich erinnerte , Folgendes verwenden:

set -x

Dies aktiviert das Debuggen. Sie können es dann wieder ausschalten mit:

set +x

(Sie können den aktuellen Ablaufverfolgungsstatus ermitteln, indem Sie $-die aktuellen Flags analysieren x.)

Außerdem bieten Shells im Allgemeinen die Optionen ' -n' für 'keine Ausführung' und ' -v' für den 'ausführlichen' Modus. Sie können diese in Kombination verwenden, um festzustellen, ob die Shell glaubt, dass sie Ihr Skript ausführen könnte - gelegentlich nützlich, wenn Sie irgendwo ein unausgeglichenes Zitat haben.


Es besteht die Behauptung, dass sich die -xOption ' ' in Bash von anderen Shells unterscheidet (siehe Kommentare). Das Bash-Handbuch sagt:

  • -x

    Drucken Sie eine Spur einfacher Befehle, forBefehle, caseBefehle, selectBefehle und arithmetischer forBefehle sowie deren Argumente oder zugehöriger Wortlisten, nachdem sie erweitert und ausgeführt wurden. Der Wert der PS4Variablen wird erweitert und der resultierende Wert wird vor dem Befehl und seinen erweiterten Argumenten gedruckt.

Das scheint überhaupt kein anderes Verhalten anzuzeigen. Ich sehe keine anderen relevanten Verweise auf ' -x' im Handbuch. Es werden keine Unterschiede in der Startsequenz beschrieben.

Erläuterung : Auf Systemen wie einer typischen Linux-Box, bei der ' /bin/sh' ein Symlink zu ' /bin/bash' ist (oder wo immer die ausführbare Bash-Datei gefunden wird), erzielen die beiden Befehlszeilen den gleichen Effekt wie das Ausführen des Skripts mit aktivierter Ausführungsablaufverfolgung. Auf anderen Systemen (z. B. Solaris und einigen moderneren Linux-Varianten) /bin/shist Bash nicht vorhanden, und die beiden Befehlszeilen würden (geringfügig) unterschiedliche Ergebnisse liefern. Vor allem /bin/shwürde ' ' durch Konstrukte in Bash verwirrt, die es überhaupt nicht erkennt. (Unter Solaris /bin/shhandelt es sich um eine Bourne-Shell. Unter modernem Linux handelt es sich manchmal um Dash - eine kleinere, strengere POSIX-Shell.) Wenn der Name wie folgt aufgerufen wird, die 'shebang'-Zeile (' #!/bin/bash'vs '#!/bin/sh' '

Das Bash-Handbuch enthält einen Abschnitt zum Bash-POSIX-Modus , der im Gegensatz zu einer langjährigen, aber fehlerhaften Version dieser Antwort (siehe auch die folgenden Kommentare) den Unterschied zwischen "Bash aufgerufen als sh" und "Bash aufgerufen als" ausführlich beschreibt bash'.

Beim Debuggen eines (Bash-) Shell-Skripts ist es sinnvoll und vernünftig - sogar notwendig -, die in der Shebang-Zeile angegebene Shell mit der -xOption zu verwenden. Andernfalls kann (wird?) Beim Debuggen ein anderes Verhalten auftreten als beim Ausführen des Skripts.

Jonathan Leffler
quelle
1
Er hat ein bashSkript angegeben. Wenn Sie ein Bash-Skript mit sh -xausführen, verhält es sich völlig anders! Bitte aktualisieren Sie Ihre Antwort.
lhunath
1
@lhunath: Inwiefern bewirkt 'sh -x' (oder 'bash -x'), dass sich ein Skript völlig anders verhält? Offensichtlich gibt es Trace-Informationen an stderr aus; Das ist eine Selbstverständlichkeit (obwohl in meiner Antwort nicht erwähnt). Aber was noch? Ich verwende 'bash' als 'sh' unter Linux und MacOS X und habe kein ernstes Problem bemerkt.
Jonathan Leffler
6
Es gibt Unterschiede beim Start und zur Laufzeit. Sie sind vollständig in der Bash-Distribution dokumentiert.
TheBonsai
4
Hier ist ein Link zum Bash-Dokument: gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files 'Wenn Bash mit dem Namen sh aufgerufen wird, versucht es, das Startverhalten historischer Versionen von sh as nachzuahmen so nah wie möglich, unter Einhaltung des Posix-Standards '
Thethinman
6
Und verwenden Sie die PS4-Eingabeaufforderung, um weitere nützliche Informationen zu geben, wie:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani
28

Ich habe die folgenden Methoden verwendet, um mein Skript zu debuggen.

set -eLässt das Skript sofort anhalten, wenn ein externes Programm einen Exit-Status ungleich Null zurückgibt. Dies ist nützlich, wenn Ihr Skript versucht, alle Fehlerfälle zu behandeln, und wenn ein Fehler aufgetreten ist.

set -x wurde oben erwähnt und ist sicherlich die nützlichste aller Debugging-Methoden.

set -n Dies kann auch nützlich sein, wenn Sie Ihr Skript auf Syntaxfehler überprüfen möchten.

straceist auch nützlich, um zu sehen, was los ist. Besonders nützlich, wenn Sie das Skript nicht selbst geschrieben haben.


quelle
1
Das Stracing eines Skripts (dh das Stracing einer Shell, die das Skript ausführt) ist eine seltsame Shell-Debugging-Methode (kann jedoch bei einer begrenzten Anzahl von Problemen funktionieren).
TheBonsai
1
Ich gebe zu, es ist seltsam und auch sehr ausführlich, aber wenn Sie die Ausgabe von strace auf einige Systemaufrufe beschränken, wird es nützlich.
1
Beachten Sie, dass dies strace -ferforderlich ist, wenn Sie auch Fehler in den vom Skript gestarteten Prozessen finden möchten. (was es um ein Vielfaches ausführlicher macht, aber dennoch nützlich ist, wenn Sie es auf die Syscalls beschränken, an denen Sie interessiert sind).
Random832
set -eist ... kontrovers .
Charles Duffy
12

Diese Antwort ist gültig und nützlich: https://stackoverflow.com/a/951352

Ich finde jedoch, dass die "Standard" -Skript-Debugging-Methoden ineffizient, nicht intuitiv und schwer zu verwenden sind. Für diejenigen, die an ausgefeilte GUI-Debugger gewöhnt sind, die alles zur Hand haben und die Arbeit für einfache Probleme zum Kinderspiel machen (und für schwierige Probleme möglich sind), sind diese Lösungen nicht sehr zufriedenstellend.

Ich verwende eine Kombination aus DDD und bashdb. Ersteres führt Letzteres aus, und Letzteres führt Ihr Skript aus. Dies bietet eine Benutzeroberfläche mit mehreren Fenstern die Möglichkeit, Code im Kontext zu durchlaufen und Variablen, Stapel usw. anzuzeigen, ohne die ständige mentale Anstrengung, den Kontext in Ihrem Kopf beizubehalten oder die Quelle immer wieder neu aufzulisten.

Hier finden Sie Anleitungen zum Einrichten: http://ubuntuforums.org/showthread.php?t=660223

Stallhund
quelle
Gerade entdeckt ddd dank Ihrer Antwort. In Ubuntu 12.04.3 (64 Bit) funktioniert die Apt-Source-Version nicht. Ich musste aus dem Quellcode kompilieren und installieren, um mit dem Debuggen meines Bash-Skripts zu beginnen. Die Anweisungen hier - askubuntu.com/questions/156906/… haben geholfen.
Chronodekar
Ja, das ist ein Problem. Ich habe es vor einiger Zeit mit einigen Skripten gelöst - 'dddbash' installiert / baut DDD, entfernt die alte Version, wenn sie falsch ist, installiert bashdb usw. (Antwort wurde jetzt mit diesen Informationen bearbeitet)
Stabledog
10

Sie können auch "set -x" in das Skript schreiben.

Cheeto
quelle
4
Und Sie können 'set + x' schreiben, um es auszuschalten.
Jonathan Leffler
10

Ich habe das Shellcheck-Dienstprogramm gefunden und vielleicht finden es einige Leute interessant https://github.com/koalaman/shellcheck

Ein kleines Beispiel:

$ cat test.sh 
ARRAY=("hello there" world)

for x in $ARRAY; do
  echo $x
done

$ shellcheck test.sh 

In test.sh line 3:
for x in $ARRAY; do
         ^-- SC2128: Expanding an array without an index only gives the first element.

Beheben Sie den Fehler, versuchen Sie es zuerst ...

$ cat test.sh       
ARRAY=("hello there" world)

for x in ${ARRAY[@]}; do
  echo $x
done

$ shellcheck test.sh

In test.sh line 3:
for x in ${ARRAY[@]}; do
         ^-- SC2068: Double quote array expansions, otherwise they're like $* and break on spaces.

Lass es uns erneut versuchen...

$ cat test.sh 
ARRAY=("hello there" world)

for x in "${ARRAY[@]}"; do
  echo $x
done

$ shellcheck test.sh

jetzt finden!

Es ist nur ein kleines Beispiel.

Gleichungslöser
quelle
1
Und es ist online !
Nick Westgate
Glücklicherweise hat sich das Tool so weit entwickelt, dass es auch den verbleibenden Fehler findet.
Tripleee
3

Installieren Sie VSCode , fügen Sie dann die Bash-Debug-Erweiterung hinzu, und Sie können im visuellen Modus debuggen. siehe hier in Aktion.

Geben Sie hier die Bildbeschreibung ein

yantaq
quelle
3

Verwenden Sie Eclipse mit den Plugins Shelled & Basheclipse.

https://sourceforge.net/projects/shelled/?source=directory https://sourceforge.net/projects/basheclipse/?source=directory

Für geschälte: Laden Sie die Zip-Datei herunter und importieren Sie sie über die Hilfe in Eclipse -> Neue Software installieren: Lokales Archiv Für Basheclipse: Kopieren Sie die Gläser in das Dropins-Verzeichnis von Eclipse

Befolgen Sie die Schritte unter https://sourceforge.net/projects/basheclipse/files/?source=navbar

Geben Sie hier die Bildbeschreibung ein

Ich habe ein Tutorial mit vielen Screenshots unter http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html geschrieben

Dietrich Schroff
quelle
2
Dies ist eine reine Linkantwort (siehe auch hier ). Sie sollten Ihre Antwort erweitern, um hier so viele Informationen wie möglich aufzunehmen, zumindest das Minimum, das erforderlich ist, um das zu erreichen, was Sie vorschlagen, und die Links nur als Referenz verwenden. Grundsätzlich müssen Beiträge zum Stapelüberlauf (und zum gesamten Stapelaustausch) in sich geschlossen sein. Das heißt , dass genügend Informationen Bedürfnisse in Ihrer Antwort sein , so dass der Leser nicht nicht zu brauchen nach dem Weg zu gehen off-site. Im Moment ist das bei dieser Antwort nicht der Fall.
Makyen
Dies ist die erste Antwort, die ich gefunden habe, nachdem ich mir viele angesehen habe, die tatsächlich zeigen, dass echtes Debuggen möglich ist. Die Standardantworten "set + x" stimmen perfekt mit einer in sich geschlossenen Antwort überein, ignorieren jedoch fast absichtlich die wahren Fragen zum echten Debuggen. Ich begrüße diese Antwort 👏
simbo1905
2

Ich habe einen Bash-Debugger gebaut. Probieren Sie es einfach aus. Ich hoffe, es wird https://sourceforge.net/projects/bashdebugingbash helfen

abadjm
quelle
BDB wird derzeit in Englisch und Spanisch unterstützt. Um die Sprache zu ändern, bearbeiten Sie die Datei / etc / default / bdb
abadjm
Der Screenshot sieht interessant aus, aber ich konnte ihn nicht zum Laufen bringen. "bdb.sh: Zeile 32: bdbSTR [1]: ungebundene Variable"; Übrigens werden die aktuellen Werte aller gesetzten Variablen bei jedem Schritt angezeigt, den wir im Code ausführen?
Wassermann Power
2

setze + x = @ECHO AUS, setze -x = @ECHO EIN.


Sie können -xvdem Standard-Shebang die folgende Option hinzufügen :

#!/bin/bash -xv  

-x: Zeigt Befehle und ihre Argumente an, während sie ausgeführt werden.
-v: Shell-Eingabezeilen beim Lesen anzeigen.


ltraceist ein anderes Linux-Dienstprogramm ähnlich strace. Allerdings ltracelistet alle Bibliotheksaufrufe in einer ausführbaren Datei oder einem laufenden Prozess aufgerufen wird. Sein Name selbst stammt von der Verfolgung von Bibliotheksaufrufen. Beispielsweise:

ltrace ./executable <parameters>  
ltrace -p <PID>  

Quelle

Premraj
quelle
1

Ein Trick zum Debuggen Skripte:

Verwenden von set -[nvx]

Zusätzlich zu

set -x

und

set +x

zum Stoppen der Müllkippe.

Ich möchte darüber sprechen, set -vwelcher Dump so klein wie weniger entwickelte Ausgabe ist.

bash <<<$'set -x\nfor i in {0..9};do\n\techo $i\n\tdone\nset +x' 2>&1 >/dev/null|wc -l
21

for arg in x v n nx nv nvx;do echo "- opts: $arg"
    bash 2> >(wc -l|sed s/^/stderr:/) > >(wc -l|sed s/^/stdout:/) <<eof
        set -$arg
        for i in {0..9};do
            echo $i
          done
        set +$arg
        echo Done.
eof
    sleep .02
  done
- opts: x
stdout:11
stderr:21
- opts: v
stdout:11
stderr:4
- opts: n
stdout:0
stderr:0
- opts: nx
stdout:0
stderr:0
- opts: nv
stdout:0
stderr:5
- opts: nvx
stdout:0
stderr:5

Dump-Variablen oder Tracing im laufenden Betrieb

Zum Testen einiger Variablen verwende ich manchmal Folgendes:

bash <(sed '18ideclare >&2 -p var1 var2' myscript.sh) args

zum Hinzufügen:

declare >&2 -p var1 var2

in Zeile 18 und Ausführen des resultierenden Skripts (mit Argumenten ), ohne sie bearbeiten zu müssen.

Dies könnte natürlich verwendet werden, um Folgendes hinzuzufügen set [+-][nvx]:

bash <(sed '18s/$/\ndeclare -p v1 v2 >\&2/;22s/^/set -x\n/;26s/^/set +x\n/' myscript) args

wird declare -p v1 v2 >&2nach Zeile 18, set -xvor Zeile 22 und set +xvor Zeile 26 hinzugefügt .

kleine Probe:

bash <(sed '2,3s/$/\ndeclare -p LINENO i v2 >\&2/;5s/^/set -x\n/;7s/^/set +x\n/' <(
        seq -f 'echo $@, $((i=%g))' 1 8)) arg1 arg2
arg1 arg2, 1
arg1 arg2, 2
declare -i LINENO="3"
declare -- i="2"
/dev/fd/63: line 3: declare: v2: not found
arg1 arg2, 3
declare -i LINENO="5"
declare -- i="3"
/dev/fd/63: line 5: declare: v2: not found
arg1 arg2, 4
+ echo arg1 arg2, 5
arg1 arg2, 5
+ echo arg1 arg2, 6
arg1 arg2, 6
+ set +x
arg1 arg2, 7
arg1 arg2, 8

Hinweis: Sorgfalt über $LINENOwird durch folgende Faktoren beeinträchtigt werden , on-the-fly Änderungen!

(Um das resultierende Skript ohne Ausführung zu sehen, lassen Sie es einfach fallen bash <(und ) arg1 arg2)

Schritt für Schritt Ausführungszeit

Schauen Sie sich meine Antwort zum Profilieren von Bash-Skripten an

F. Hauri
quelle
0

Es gibt viele Details zur Protokollierung von Shell-Skripten über globale Shell-Variablen. Wir können die ähnliche Art der Protokollierung im Shell-Skript emulieren: http://www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html

Der Beitrag enthält Details zum Einführen von Protokollstufen wie INFO, DEBUG, ERROR. Verfolgungsdetails wie Skripteintrag, Skriptexit, Funktionseingang, Funktionsexit.

Beispielprotokoll:

Geben Sie hier die Bildbeschreibung ein

Piyush Chordia
quelle