C'è un modo per eseguire il debug di uno script bash? Ad esempio qualcosa che stampa una sorta di registro di esecuzione come "linea chiamante 1", "linea chiamante 2" ecc.
C'è un modo per eseguire il debug di uno script bash? Ad esempio qualcosa che stampa una sorta di registro di esecuzione come "linea chiamante 1", "linea chiamante 2" ecc.
Risposte:
sh -x script [arg1 ...]
bash -x script [arg1 ...]
Questi ti danno una traccia di ciò che viene eseguito. (Vedi anche "Chiarimento" nella parte inferiore della risposta.)
A volte, è necessario controllare il debug all'interno dello script. In tal caso, come mi ha ricordato Cheeto , puoi usare:
set -x
Questo attiva il debug. È quindi possibile disattivarlo di nuovo con:
set +x
(È possibile scoprire lo stato di traccia corrente analizzando $-, i flag correnti, per x.)
Inoltre, le shell generalmente forniscono le opzioni ' -n' per 'nessuna esecuzione' e ' -v' per la modalità 'dettagliata'; puoi usarli in combinazione per vedere se la shell pensa che potrebbe eseguire il tuo script - a volte utile se hai una citazione sbilanciata da qualche parte.
Si sostiene che l' -xopzione ' ' in Bash sia diversa dalle altre shell (vedere i commenti). Il manuale di Bash dice:
-X
Stampa una traccia di semplici comandi, forcomandi, casecomandi, selectcomandi e forcomandi aritmetici e i loro argomenti o elenchi di parole associati dopo che sono stati espansi e prima che vengano eseguiti. Il valore della PS4variabile viene espanso e il valore risultante viene stampato prima del comando e dei suoi argomenti espansi.
Questo sembra non indicare affatto un comportamento diverso. Non vedo altri riferimenti rilevanti a " -x" nel manuale. Non descrive le differenze nella sequenza di avvio.
Chiarimento : su sistemi come un tipico box Linux, dove ' /bin/sh' è un collegamento simbolico a ' /bin/bash' (o ovunque si trovi l'eseguibile di Bash), le due linee di comando ottengono l'effetto equivalente di eseguire lo script con la traccia di esecuzione attiva. Su altri sistemi (ad esempio, Solaris, e alcune varianti più moderne di Linux), /bin/shnon c'è Bash e le due linee di comando darebbero (leggermente) risultati diversi. In particolare, " /bin/sh" sarebbe confuso dai costrutti in Bash che non riconosce affatto. (Su Solaris, /bin/shè una shell Bourne; su Linux moderno, a volte è Dash - una shell più piccola, più strettamente solo POSIX.) Quando invocata da un nome come questo, la riga 'shebang' (' #!/bin/bash' vs '#!/bin/sh'
Il manuale di Bash ha una sezione sulla modalità POSIX di Bash che, contrariamente a una versione di vecchia data ma errata di questa risposta (vedere anche i commenti sotto), descrive in modo dettagliato la differenza tra "Bash invocato come sh" e "Bash invocato come bash'.
Quando si esegue il debug di uno script di shell (Bash), sarà sensato e sensato - anche necessario - utilizzare la shell denominata nella riga shebang con l' -xopzione. Altrimenti, è possibile (sarà?) Avere un comportamento diverso durante il debug da quando si esegue lo script.
bashsceneggiatura. E l'esecuzione di uno script bash sh -xfarà sì che si comporti in modo completamente diverso! Aggiorna la tua risposta.
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
Ho usato i seguenti metodi per eseguire il debug del mio script.
set -efa arrestare immediatamente lo script se un programma esterno restituisce uno stato di uscita diverso da zero. Ciò è utile se lo script tenta di gestire tutti i casi di errore e in cui un errore deve essere intrappolato.
set -x è stato menzionato sopra ed è sicuramente il più utile di tutti i metodi di debug.
set -n potrebbe anche essere utile se si desidera controllare lo script per errori di sintassi.
straceè utile anche per vedere cosa sta succedendo. Particolarmente utile se non hai scritto tu stesso la sceneggiatura.
strace -fè necessario se si desidera trovare anche errori nei processi avviati dallo script. (il che lo rende molte volte più dettagliato, ma comunque utile se lo limiti alle syscalls che ti interessano).
set -eè ... controverciale .
Questa risposta è valida e utile: https://stackoverflow.com/a/951352
Tuttavia, trovo che i metodi di debug degli script "standard" siano inefficienti, non intuitivi e difficili da usare. Per coloro che sono abituati a sofisticati debugger della GUI che mettono tutto a portata di mano e rendono il lavoro un gioco da ragazzi per problemi facili (e possibili per problemi difficili), queste soluzioni non sono molto soddisfacenti.
Quello che faccio è usare una combinazione di DDD e bashdb. Il primo esegue il secondo e il secondo esegue il tuo script. Ciò fornisce un'interfaccia utente multi-finestra con la possibilità di scorrere il codice nel contesto e visualizzare variabili, stack, ecc., Senza il costante sforzo mentale di mantenere il contesto nella propria testa o continuare a reinserire la fonte.
C'è una guida per l'impostazione qui: http://ubuntuforums.org/showthread.php?t=660223
Puoi anche scrivere "set -x" all'interno dello script.
Ho trovato l'utilità shellcheck e alcune persone potrebbero trovarlo interessante https://github.com/koalaman/shellcheck
Un piccolo esempio:
$ 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.
correggi il bug, prima prova ...
$ 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.
Proviamo di nuovo...
$ cat test.sh
ARRAY=("hello there" world)
for x in "${ARRAY[@]}"; do
echo $x
done
$ shellcheck test.sh
trova adesso!
È solo un piccolo esempio.
Usa eclipse con i plugin sgusciati e basheclipse.
https://sourceforge.net/projects/shelled/?source=directory https://sourceforge.net/projects/basheclipse/?source=directory
Per shelled: scarica lo zip e importalo in eclipse tramite aiuto -> installa nuovo software: archivio locale per basheclipse: copia i vasetti nella directory dropins di eclipse
Seguire i passaggi forniti https://sourceforge.net/projects/basheclipse/files/?source=navbar
Ho scritto un tutorial con molti screenshot su http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html
Ho creato un debugger Bash. Basta fare un tentativo. Spero che possa aiutare https://sourceforge.net/projects/bashdebugingbash
set + x = @ECHO OFF, set -x = @ECHO ON.
Puoi aggiungere l' -xvopzione allo standard Shebang come segue:
#!/bin/bash -xv
-x: Visualizza i comandi e i relativi argomenti mentre vengono eseguiti.
-v: Visualizza le righe di input della shell mentre vengono lette.
ltraceè un'altra utility Linux simile a strace. Tuttavia, ltraceelenca tutte le chiamate della libreria chiamate in un eseguibile o in un processo in esecuzione. Il nome stesso deriva dalla traccia delle chiamate in libreria. Per esempio:
ltrace ./executable <parameters>
ltrace -p <PID>
Penso che tu possa provare questo debugger di Bash: http://bashdb.sourceforge.net/ .
set -[nvx]Inoltre
set -x
e
set +x
per fermare la discarica.
Vorrei parlare di un set -vdump più piccolo di un output meno sviluppato.
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
Per testare alcune variabili, a volte uso questo:
bash <(sed '18ideclare >&2 -p var1 var2' myscript.sh) args
per aggiungere:
declare >&2 -p var1 var2
alla riga 18 ed eseguendo lo script risultante (con args ), senza doverli modificare.
ovviamente, questo potrebbe essere usato per aggiungere set [+-][nvx]:
bash <(sed '18s/$/\ndeclare -p v1 v2 >\&2/;22s/^/set -x\n/;26s/^/set +x\n/' myscript) args
verrà aggiunto declare -p v1 v2 >&2dopo la riga 18, set -xprima della riga 22 e set +xprima della riga 26.
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
Nota: la cura $LINENOsarà influenzata da modifiche al volo !
(Per visualizzare lo script risultante senza eseguire, rilasciare bash <(e ) arg1 arg2)
Dai un'occhiata alla mia risposta su come creare un profilo degli script bash
C'è una buona quantità di dettagli sulla registrazione per gli script di shell tramite le variabili globali di shell. Possiamo emulare lo stesso tipo di registrazione nello script della shell: http://www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html
Il post contiene dettagli sull'introduzione di livelli di log come INFO, DEBUG, ERROR. Tracciare dettagli come voce di script, uscita di script, voce di funzione, uscita di funzione.
Registro di esempio: