Come eseguire il debug di uno script bash? [chiuso]


159

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:


195
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.


1
Ha specificato una bashsceneggiatura. E l'esecuzione di uno script bash sh -xfarà sì che si comporti in modo completamente diverso! Aggiorna la tua risposta.
lhunath,

1
@lhunath: In che modo 'sh -x' (o 'bash -x') fa in modo che uno script si comporti in modo completamente diverso? Ovviamente, invia informazioni di traccia a stderr; questo è un dato (anche se non menzionato nella mia risposta). Ma cos'altro? Uso "bash" come "sh" su Linux e MacOS X e non ho notato un problema serio.
Jonathan Leffler,

6
Ci sono differenze, in avvio e in fase di esecuzione. Sono completamente documentati nella distribuzione di Bash.
TheBonsai

4
Ecco un link al doc bash: gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files 'Se Bash viene invocato con il nome sh, cerca di imitare il comportamento di avvio delle versioni storiche di sh as il più vicino possibile, pur rispettando anche lo standard posix '
thinman il

6
E usa il prompt di PS4 per fornire informazioni più utili come:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani,

28

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.


1
Stracing uno script (ovvero stracing una shell che esegue lo script) è uno strano metodo di debug della shell (ma può funzionare per un numero limitato di problemi).
TheBonsai

1
Devo ammettere che è strano e anche molto prolisso, ma se si limita l'output di strace a qualche syscalls, diventa utile.

1
Si noti che 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).
Casuale 832

set -eè ... controverciale .
Charles Duffy,

12

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


Ho appena scoperto ddd grazie alla tua risposta. In Ubuntu 12.04.3 (64 bit), la versione di apt-source non funziona. Ho dovuto compilare e installare dal sorgente per iniziare il debug del mio script bash. Le istruzioni qui - askubuntu.com/questions/156906/… sono state di aiuto.
chronodekar,

Sì, questo è un problema. L'ho risolto qualche tempo fa con alcuni script - 'dddbash' installa / costruisce DDD, rimuove la vecchia versione se è sbagliata, installa bashdb, ecc. (La risposta è stata modificata con queste informazioni ora)
Stabledog


10

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.


1
Ed è online !
Nick Westgate,

Fortunatamente lo strumento si è evoluto al punto da trovare anche il bug rimanente.
Tripleee

3

Installa VSCode , quindi aggiungi l'estensione di debug bash e sei pronto per eseguire il debug in modalità visiva. vedi qui in azione.

inserisci qui la descrizione dell'immagine


3

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

inserisci qui la descrizione dell'immagine

Ho scritto un tutorial con molti screenshot su http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html


2
Questa è una risposta solo al collegamento borderline (vedi anche qui ). Dovresti espandere la tua risposta per includere quante più informazioni possibili qui, almeno il minimo necessario per realizzare effettivamente ciò che stai suggerendo e usare i collegamenti solo come riferimento. Fondamentalmente, i post su Stack Overflow (e tutto lo Stack Exchange) devono essere autonomi. Ciò significa che nella tua risposta devono essere presenti informazioni sufficienti in modo tale che il lettore non debba andare fuori sede per ricevere indicazioni. In questo momento, non è il caso di questa risposta.
Makyen

questa è la prima risposta che ho trovato dopo aver esaminato molti che in realtà dimostra che il vero debugging è possibile. Le risposte standard "set + x" corrispondono perfettamente a una risposta autonoma, ma ignorano quasi volontariamente le vere domande sul vero debug. Applaudo questa risposta 👏
simbo1905,

2

Ho creato un debugger Bash. Basta fare un tentativo. Spero che possa aiutare https://sourceforge.net/projects/bashdebugingbash


BDB è attualmente supportato in inglese e spagnolo. Per cambiare la lingua, modifica il file / etc / default / bdb
abadjm

lo screenshot sembra interessante ma non sono riuscito a farlo funzionare "bdb.sh: line 32: bdbSTR [1]: variabile non associata"; tra l'altro mostrerà i valori correnti di tutte le variabili impostate ogni passo che facciamo sul codice?
Aquarius Power il

2

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>  

fonte



1

Qualche trucco per il debug script:

utilizzando 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

Scarica variabili o traccia al volo

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.

piccolo campione:

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)

Passo dopo passo, tempo di esecuzione

Dai un'occhiata alla mia risposta su come creare un profilo degli script bash


0

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:

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.