GNU/Linux >> Linux Esercitazione >  >> Linux

Come eseguire il debug di script Bash in Linux e Unix

Il debug ti aiuta a correggere gli errori nel tuo programma. In questo articolo, discuteremo vari metodi per eseguire il debug degli script bash nei sistemi operativi Linux e Unix.

Introduzione

Nei miei primi giorni di programmazione, ho passato ore a cercare di trovare l'errore nel mio codice e, alla fine, potrebbe essere qualcosa di semplice. Potresti aver affrontato la stessa situazione anche tu.

Sapere come utilizzare la tecnica di debug corretta ti aiuterebbe a risolvere rapidamente gli errori. A differenza di altri linguaggi come Python, Java, ecc. non esiste uno strumento di debugger per bash in cui puoi impostare punti di interruzione, eseguire il passaggio del codice, ecc.

Ci sono alcune funzionalità integrate che aiutano a eseguire il debug degli script della shell bash. Vedremo in dettaglio queste funzionalità nelle prossime sezioni.

Tre modi per utilizzare le opzioni di debug

Quando vuoi abilitare le opzioni di debug nei tuoi script, puoi farlo in tre modi.

1 . Abilita le opzioni di debug dalla shell del terminale quando chiami lo script.

$ bash [ debugging flags ] scriptname

2 . Abilita le opzioni di debug passando i flag di debug alla riga shebang nello script.

#!/bin/bash [ debugging flags ]

3 . Abilita le opzioni di debug usando il set comando dallo script.

set -o nounset
set -u

A cosa serve il comando Imposta?

Il set command è un comando integrato nella shell che può essere utilizzato per controllare i parametri bash e modificare il comportamento di bash in determinati modi.

Normalmente non eseguirai i comandi set dal terminale per alterare il comportamento della shell. Sarà ampiamente utilizzato all'interno degli script di shell sia per il debug che per abilitare la modalità bash strict.

$ type -a set
set is a shell builtin

Puoi accedere alla sezione della guida del comando set per sapere quali flag supporta e cosa fa ogni flag.

$ set --help

Esegui il debug di una parte dello script o dello script completo

Prima di conoscere le opzioni di debug, devi capire che puoi eseguire il debug dell'intero script o solo di una determinata parte del codice. Devi usare il comando set per abilitare e disabilitare le opzioni di debug.

  • set -<debugging-flag> abiliterà la modalità di debug.
  • set +<debugging-flag> disabiliterà la modalità di debug.

Dai un'occhiata al codice qui sotto. set -x abiliterà la modalità xtrace per lo script e set +x disabiliterà la modalità xtrace. Tutto ciò che si trova tra set -x e set +x verrà eseguito in modalità di debug xtrace.

Imparerai la modalità xtrace nella prossima sezione. Quindi, per qualsiasi flag di debug, l'unica cosa che devi ricordare è, set - abiliterà la modalità e set + disabiliterà la modalità.

#!/bin/bash

set -x
read -p "Pass Dir name : " D_OBJECT
read -p "Pass File name : " F_OBJECT
set +x

touch ${D_OBJECT}/${F_OBJECT}

Fallito se non è definita alcuna variabile

Quando lavori con variabili in bash , lo svantaggio è che se proviamo a utilizzare una variabile non definita, lo script non fallirà con alcuni messaggi di errore come "Variabile non definita" . Invece stamperà una stringa vuota.

Dai un'occhiata al codice seguente in cui ricevo input dall'utente e lo memorizzo nella variabile $OBJECT . Ho provato a eseguire l'operatore di test (-f e -d ) sul $OBJECT1 variabile non definita.

#!/bin/bash

read -p "Please provide the object name :  " OBJECT
if [[ -f $OBJECT1 ]]
then
    echo "$OBJECT is a file"
elif [[ -d $OBJECT1 ]]
then
    echo "$OBJECT is a directory"
fi

Quando eseguo questo codice, dovrebbe avermi generato un errore ma non è stato così e anche lo script è uscito con il codice di ritorno zero.

Per ignorare questo comportamento, usa -u flag che genererà un errore quando viene utilizzata una variabile non definita.

Eseguirò di nuovo lo stesso codice con il nome della variabile sbagliato ma questa volta genererà una "Variabile non associata" errore.

Puoi anche impostare il -u opzione utilizzando il set comandalo o passalo come argomento allo shebang.

set -u
set -o nounset

(o)

#! /bin/bash -u

Modalità Xtrace in soccorso

Questa è la modalità che uso ampiamente quando eseguo il debug degli script bash per errori logici. Xtrace la modalità visualizzerà il codice riga per riga ma con i parametri espansi.

Nella sezione precedente, quando ho eseguito il codice senza -u flag, è stato completato con successo ma mi aspettavo l'output nel terminale. Ora posso eseguire lo stesso script in modalità xtrace e vedere esattamente dove si verifica il problema nello script.

Dai un'occhiata al seguente codice di esempio.

#!/bin/bash

read -p "Please provide the object name :  " OBJECT
if [[ -f $OBJECT1 ]]
then
    echo "$OBJECT is a file"
elif [[ -d $OBJECT1 ]]
then
    echo "$OBJECT is a directory"
fi

Quando eseguo il codice sopra, non mi restituisce alcun output.

Per eseguire il debug di questo problema, posso eseguire lo script in xtrace mode passando il -x bandiera.

Nell'output sottostante, puoi vedere le variabili espanse e stampate. Questo mi dice che ci sono stringhe vuote assegnate alle istruzioni condizionali -f e -d . In questo modo posso logicamente controllare e correggere gli errori.

Il segno più che vedi nell'output può essere modificato impostando il PS4 variabile nello script. Per impostazione predefinita, PS4 è impostata su (+ ).

$ echo $PS4
+
$ PS4=" ==> " bash -x debugging.sh

Puoi anche impostare la modalità Xtrace usando il comando set o passarlo come argomento allo shebang.

set -x
set -o xtrace

(o)

#! /bin/bash -x

Allo stesso modo, durante il debug è possibile reindirizzare i log di debug di Xtrace su un file invece di stamparli sul terminale.

Dai un'occhiata al codice qui sotto. Sto assegnando un descrittore di file 6 al .log file e BASH_XTRACEFD="6" reindirizzerà i log di debug di xtrace al descrittore di file 6.

#!/bin/bash


exec 6> redirected_debug.log 
PS4=' ==> ' 
BASH_XTRACEFD="6" 
read -p "Please provide the object name :  " OBJECT
if [[ -f $OBJECT1 ]]
then
    echo "$OBJECT is a file"
elif [[ -d $OBJECT1 ]]
then
    echo "$OBJECT is a directory"
fi

Quando eseguo questo codice invece di stampare l'output di xtrace nel terminale, verrà reindirizzato a .log file.

$ cat redirected_debug.log 
==> read -p 'Please provide the object name :  ' OBJECT
==> [[ -f '' ]]
==> [[ -d '' ]]

Stato uscita TUBO

Il comportamento predefinito quando si utilizza una pipe è che prenderà il codice di uscita dell'ultimo comando di esecuzione nella pipe. Anche se i comandi precedenti nella pipe non sono riusciti, eseguirà il resto della pipe.

Dai un'occhiata all'esempio qui sotto. Ho provato ad aprire un file che non è disponibile e a inviarlo tramite pipe con un conteggio parole programma. Anche se il cat comando genera un errore, il programma di conteggio delle parole viene eseguito.

Se provi a controllare il codice di uscita dell'ultimo comando run pipe utilizzando $? , otterrai zero come codice di uscita che proviene dal programma di conteggio delle parole.

$ cat nofile.txt | wc -l
cat: nofile.txt: No such file or directory
0
$ echo $?
0

Quando pipefail è abilitato nello script, se un comando genera un codice di ritorno diverso da zero nella pipe, verrà considerato come il codice di ritorno per l'intera pipeline. Puoi abilitare pipefail aggiungendo la seguente proprietà set nel tuo script.

set -o pipefail

C'è ancora un problema con questo approccio. Normalmente ciò che dovrebbe essere previsto è che se un comando nella pipe non riesce, lo script dovrebbe uscire senza eseguire il resto del comando nella pipe.

Ma sfortunatamente, anche se un comando non riesce, il comando successivo nella pipe viene eseguito. Questo perché ogni comando nella pipe viene eseguito nella propria subshell. La shell attenderà il completamento di tutti i processi nella pipe, quindi restituirà il risultato.

Modalità Bash Strict

Per eliminare tutti i possibili errori che abbiamo visto nelle sezioni precedenti si consiglia di aggiungere le seguenti opzioni in ogni script.

Abbiamo già discusso in dettaglio tutte queste opzioni nella sezione precedente.

  • -e flag => Esci dallo script se un comando genera un codice di uscita diverso da zero.
  • -u flag => Fai fallire lo script se viene utilizzato un nome di variabile non definito.
  • pipefail => Se un comando nella pipeline non riesce, il codice di uscita verrà considerato per l'intera pipeline.
  • IFS => Separatore di campo interno, impostandolo su newline(\n) e (\t) la divisione avviene solo in newline e tab.
set -e
set -u
set -o pipefail

Oppure

set -euo pipefail
IFS=$'\n\t'

Cattura segnali usando TRAP

Trappola ti consente di acquisire segnali nel tuo script bash e di intraprendere alcune azioni di conseguenza.

Pensa a uno scenario in cui attivi lo script ma desideri annullare lo script utilizzando CTRL+C battitura. In tal caso, SIGINT verrà inviato al tuo script. Puoi catturare questo segnale ed eseguire alcuni comandi o funzioni.

Dai un'occhiata allo pseudocodice riportato di seguito. Ho creato una funzione chiamata cleanup che verrà eseguita quando SIGINT viene passato allo script.

trap 'cleanup' TERM INT
function cleanup(){
    echo "Running cleanup since user initiated CTRL + C"
    <some logic>
}

È possibile utilizzare la trap "DEBUG", che può essere utilizzata per eseguire ripetutamente un'istruzione nello script. Il modo in cui si comporta è che ogni istruzione eseguita nello script trap eseguirà la funzione o l'istruzione associata.

Puoi capirlo usando l'esempio seguente.

#!/bin/bash

trap 'printf "${LINENO} ==> DIR_NAME=${D_OBJECT} ; FILE_NAME=${F_OBJECT}; FILE_CREATED=${FILE_C} \n"' DEBUG

read -p "Pass Dir name : " D_OBJECT
read -p "Pass File name : " F_OBJECT

touch ${D_OBJECT}/${F_OBJECT} && FILE_C="Yes"
exit 0

Questo è un semplice programma che ottiene l'input dell'utente e crea un file e una directory. Il comando trap verrà eseguito per ogni istruzione nello script e stamperà gli argomenti passati e lo stato di creazione del file.

Dai un'occhiata all'output di seguito. Per ogni riga dello script, il trap viene attivato e le variabili vengono aggiornate di conseguenza.

Stampa il codice utilizzando la modalità dettagliata

In modalità dettagliata, il codice verrà stampato prima di restituire il risultato. Se il programma richiede un input interattivo, in tal caso verrà stampata da sola quella riga seguita da un blocco di codici.

Dai un'occhiata al seguente programma. È un semplice programma che ottiene un oggetto dall'utente e controlla se l'oggetto passato è un file o una directory utilizzando un'istruzione condizionale .

#!/bin/bash

read -p "Please provide the object name :  " OBJECT
if [[ -f $OBJECT ]]
then
  echo "$OBJECT is a file"
elif [[ -d $OBJECT ]]
then
  echo "$OBJECT is a directory"
fi

Quando eseguo il codice sopra, prima stamperà il codice, quindi attenderà l'input dell'utente come mostrato di seguito.

Una volta passato l'oggetto, verrà stampato il resto del codice seguito dall'output.

Puoi anche impostare la modalità dettagliata usando set o in shebang .

set -v
set -o verbose

(o)

#! /bin/bash -v

Puoi anche combinare la modalità dettagliata con altre modalità.

set -vx # Verbose and Xtrace Mode
set -uv # Verbose and Unset Mode

Convalida della sintassi - modalità noexec

Finora abbiamo visto come lavorare con gli errori logici nello script. In questa sezione, discutiamo degli errori di sintassi.

Gli errori di sintassi sono molto comuni nei programmi. Potresti aver perso una citazione o non essere riuscito a uscire dal ciclo, ecc. Puoi usare "-n " flag che si chiama noexec mode per convalidare la sintassi prima di eseguire il programma.

Eseguirò il codice seguente e convaliderò la sintassi.

#!/bin/bash

TOOLS=( htop peek tilix vagrant shutter )
for TOOL in "${TOOLS[@]" 
do
    echo "--------------INSTALLING: ${TOOL}---------------------------"
    apt install ${TOOL} -y
#done

Ci sono due errori in questo programma. In primo luogo, non sono riuscito a chiudere le parentesi graffe nel "for loop " e in secondo luogo done la parola chiave è commentata e dovrebbe segnare la fine del ciclo.

Quando eseguo questo programma, ricevo i seguenti messaggi di errore che indicano la mancanza di parentesi graffe e parola chiave completata . A volte il numero di riga indicato nel messaggio di errore non conterrà alcun errore che dovresti cercare per trovare l'errore effettivo.

$ bash -n ./debugging.sh 

./debugging.sh: line 6: unexpected EOF while looking for matching `"'
./debugging.sh: line 8: syntax error: unexpected end of file

Va notato che, per impostazione predefinita, quando esegui lo script, bash convaliderà la sintassi e genererà questi errori anche senza utilizzare la modalità noexec.

In alternativa, puoi anche utilizzare il set comando o shebang per usare noexec modalità.

set -n 
set -o noexec

Oppure,

#! /bin/bash -n

Ci sono alcuni strumenti esterni là fuori che vale la pena dare un'occhiata usati per il debug degli script. Uno di questi strumenti è Shellcheck . Shellcheck può anche essere integrato con i più diffusi editor di testo come vscode, sublime text, Atom.

Conclusione

In questo articolo, ti ho mostrato alcuni dei modi per eseguire il debug degli script bash. A differenza di altri linguaggi di programmazione, bash non ha strumenti di debug oltre ad alcune opzioni integrate. A volte queste opzioni di debug integrate saranno più che sufficienti per portare a termine il lavoro.

Guide agli script di Bash:

  • Scripting Bash:analisi degli argomenti negli script Bash utilizzando getopts
  • Come creare finestre di dialogo della GUI negli script Bash con Zenity in Linux e Unix
  • Scripting Bash – Case Statement
  • Scripting Bash – Dichiarazioni condizionali
  • Scripting Bash – Manipolazione di stringhe
  • Scripting Bash:comando Printf spiegato con esempi
  • Scripting Bash:array indicizzato spiegato con esempi
  • Scripting Bash:array associativo spiegato con esempi
  • Scripting Bash:il ciclo For viene spiegato con esempi
  • Scripting di Bash:spiegazione del ciclo While e Until con esempi
  • Il reindirizzamento di Bash spiegato con esempi
  • Scripting Bash:variabili spiegate con esempi
  • Scripting Bash:funzioni spiegate con esempi
  • Comando Bash Echo spiegato con esempi in Linux
  • Tutorial Bash Heredoc per principianti

Linux
  1. Come impostare l'indirizzo IP statico e configurare la rete in Linux

  2. Come impostare/creare variabili di ambiente e shell in Linux

  3. Come impostare, elencare e rimuovere variabili d'ambiente in Linux

  4. UNIX / Linux:come installare e configurare mutt

  5. Come impostare in modo permanente $ PATH su Linux/Unix?

Come configurare la chiave pubblica e privata SSH in Linux

Come utilizzare il comando echo negli script Bash in Linux

Come impostare data e ora su Linux

Come impostare e annullare l'impostazione delle variabili di ambiente su Linux

Come cancellare la cronologia di Bash in Linux e Mac

Come installare e configurare 1Password su desktop Linux