Cum să utilizați set și pipefail în scripturile Bash pe Linux
Publicat: 2022-06-25 Comenzile Linux set
și pipefail
dictează ce se întâmplă atunci când apare o eroare într-un script Bash. Este mai mult de gândit decât ar trebui să se oprească sau să continue.
LEGATE: Ghidul pentru începători pentru scriptarea Shell: elementele de bază
Scripturi Bash și condiții de eroare
Scripturile shell Bash sunt grozave. Sunt rapid de scris și nu au nevoie de compilare. Orice acțiune repetitivă sau în mai multe etape pe care trebuie să o efectuați poate fi înglobată într-un script convenabil. Și pentru că scripturile pot apela oricare dintre utilitățile standard Linux, nu sunteți limitat la capacitățile limbajului shell în sine.
Dar problemele pot apărea atunci când apelați un utilitar sau un program extern. Dacă nu reușește, utilitarul extern se va închide și va trimite un cod de retur către shell și ar putea chiar să imprime un mesaj de eroare pe terminal. Dar scriptul tău va continua procesarea. Poate că nu asta ți-ai dorit. Dacă apare o eroare la începutul execuției scriptului, aceasta poate duce la probleme mai grave dacă restul scriptului este permis să ruleze.
Puteți verifica codul de returnare de la fiecare proces extern pe măsură ce se completează, dar acest lucru devine dificil atunci când procesele sunt conectate la alte procese. Codul de returnare va fi din procesul de la capătul conductei, nu cel din mijloc care a eșuat. Desigur, pot apărea erori și în interiorul scriptului, cum ar fi încercarea de a accesa o variabilă neinițializată.
Comenzile set
și pipefile
vă permit să decideți ce se întâmplă atunci când apar erori ca acestea. De asemenea, vă permit să detectați erorile chiar și atunci când acestea apar în mijlocul unui lanț de țevi.
Iată cum să le folosiți.
Demonstrarea problemei
Iată un script Bash banal. Trimite două linii de text către terminal. Puteți rula acest script dacă copiați textul într-un editor și îl salvați ca „script-1.sh”.
#!/bin/bash ecou Acest lucru se va întâmpla mai întâi ecou Acest lucru se va întâmpla în al doilea rând
Pentru a-l face executabil, va trebui să utilizați chmod
:
chmod +x script-1.sh
Va trebui să rulați acea comandă pe fiecare script dacă doriți să le executați pe computer. Să rulăm scriptul:
./script-1.sh
Cele două rânduri de text sunt trimise în fereastra terminalului așa cum era de așteptat.
Să modificăm ușor scriptul. Îi vom cere lui ls
să listeze detaliile unui fișier care nu există. Acest lucru va eșua. L-am salvat ca „script-2.sh” și l-am făcut executabil.
#!/bin/bash ecou Acest lucru se va întâmpla mai întâi ls imaginary-filename ecou Acest lucru se va întâmpla în al doilea rând
Când rulăm acest script, vedem mesajul de eroare de la ls
.
./script-2.sh
Deși comanda ls
a eșuat, scriptul a continuat să ruleze. Și chiar dacă a existat o eroare în timpul execuției scriptului, codul de returnare de la script la shell este zero, ceea ce indică succesul. Putem verifica acest lucru folosind echo și $?
variabilă care deține ultimul cod de returnare trimis către shell.
eco $?
Zero care este raportat este codul de întoarcere de la al doilea ecou din script. Deci, există două probleme cu acest scenariu. Primul este că scriptul a avut o eroare, dar a continuat să ruleze. Acest lucru poate duce la alte probleme dacă restul scriptului se așteaptă sau depinde de acțiunea care a eșuat a reușit efectiv. Și al doilea este că, dacă un alt script sau proces trebuie să verifice succesul sau eșecul acestui script, va primi o citire falsă.
Opțiunea set -e
Opțiunea set -e
(ieșire) determină ieșirea unui script dacă oricare dintre procesele pe care le apelează generează un cod de returnare diferit de zero. Orice lucru diferit de zero este considerat un eșec.
Adăugând opțiunea set -e
la începutul scriptului, îi putem schimba comportamentul. Acesta este „script-3.sh”.
#!/bin/bash set -e ecou Acest lucru se va întâmpla mai întâi ls imaginary-filename ecou Acest lucru se va întâmpla în al doilea rând
Dacă rulăm acest script, vom vedea efectul set -e
.
./script-3.sh
eco $?
Scriptul este oprit și codul de returnare trimis către shell este o valoare diferită de zero.
Tratarea defecțiunilor la conducte
Conductele adaugă mai multă complexitate problemei. Codul de întoarcere care iese dintr-o secvență de comenzi canalizată este codul de returnare de la ultima comandă din lanț. Dacă există un eșec cu o comandă în mijlocul lanțului, ne întoarcem la punctul unu. Acest cod de returnare este pierdut și scriptul va continua procesarea.
Putem vedea efectele comenzilor de canalizare cu diferite coduri de returnare folosind integrate shell true
și false
. Aceste două comenzi nu fac altceva decât să genereze un cod returnat de zero sau, respectiv, unu.
Adevărat
eco $?
fals
eco $?
Dacă introducem false
în true
- cu false
reprezentând un proces care eșuează - obținem codul de returnare al lui true
de zero.
fals | Adevărat
eco $?
Bash are o variabilă matrice numită PIPESTATUS
și aceasta captează toate codurile de returnare de la fiecare program din lanțul de conducte.
fals | adevărat | fals | Adevărat
echo „${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]} ${PIPESTATUS[3]}”
PIPESTATUS
reține codurile de returnare numai până când următorul program rulează, iar încercarea de a determina ce cod de returnare se potrivește cu care program poate deveni foarte dezordonat foarte repede.
Aici intervin set -o
(opțiuni) și pipefail
. Acesta este „script-4.sh”. Aceasta va încerca să canalizeze conținutul unui fișier care nu există în wc
.
#!/bin/bash set -e ecou Acest lucru se va întâmpla mai întâi cat script-99.sh | wc -l ecou Acest lucru se va întâmpla în al doilea rând
Acest lucru eșuează, așa cum ne-am aștepta.
./script-4.sh
eco $?
Primul zero este rezultatul de la wc
, spunându-ne că nu a citit nicio linie pentru fișierul lipsă. Al doilea zero este codul de întoarcere de la a doua comandă echo
.
Vom adăuga -o pipefail
, îl vom salva ca „script-5.sh” și îl vom face executabil.
#!/bin/bash set -eo pipefail ecou Acest lucru se va întâmpla mai întâi cat script-99.sh | wc -l ecou Acest lucru se va întâmpla în al doilea rând
Să rulăm asta și să verificăm codul de returnare.
./script-5.sh
eco $?
Scriptul se oprește și a doua comandă echo
nu este executată. Codul de returnare trimis către shell este unul, indicând corect o eroare.
LEGATE: Cum să utilizați comanda Echo pe Linux
Captarea variabilelor neinițializate
Variabilele neinițializate pot fi dificil de identificat într-un script din lumea reală. Dacă încercăm să echo
echo
și simplu imprimă o linie goală. Nu afișează un mesaj de eroare. Restul scriptului va continua să se execute.
Acesta este script-6.sh.
#!/bin/bash set -eo pipefail ecou „$notset” echo „O altă comandă ecou”
Îl vom rula și îi vom observa comportamentul.
./script-6.sh
eco $?
Scriptul trece peste variabila neinițializată și continuă să se execute. Codul de returnare este zero. Încercarea de a găsi o eroare ca aceasta într-un script foarte lung și complicat poate fi foarte dificilă.
Putem prinde acest tip de eroare folosind opțiunea set -u
(unset). Vom adăuga asta la colecția noastră tot mai mare de opțiuni setate din partea de sus a scriptului, îl vom salva ca „script-7.sh” și îl vom face executabil.
#!/bin/bash set -eou pipefail ecou „$notset” echo „O altă comandă ecou”
Să rulăm scriptul:
./script-7.sh
eco $?
Variabila neinițializată este detectată, scriptul se oprește și codul de returnare este setat la unul.
Opțiunea -u
(unset) este suficient de inteligentă pentru a nu fi declanșată de situații în care puteți interacționa în mod legitim cu o variabilă neinițializată.
În „script-8.sh”, scriptul verifică dacă variabila New_Var
este inițializată sau nu. Nu doriți ca scenariul să se oprească aici, într-un scenariu din lumea reală, veți efectua procesări ulterioare și veți rezolva singur situația.
Rețineți că am adăugat opțiunea -u
ca a doua opțiune în instrucțiunea set. Opțiunea -o pipefail
trebuie să fie ultima.
#!/bin/bash set -euo pipefail dacă [ -z "${New_Var:-}" ]; apoi echo "New_Var nu are nicio valoare atribuită." fi
În „script-9.sh”, variabila neinițializată este testată și, dacă este neinițializată, este furnizată o valoare implicită.
#!/bin/bash set -euo pipefail default_value=484 Valoare=${New_Var:-$default_value} echo "New_Var=$Value"
Scripturile au voie să ruleze până la finalizarea lor.
./script-8.sh
./script-9.sh
Sigilat cu topor
O altă opțiune la îndemână de utilizat este opțiunea set -x
(execuție și imprimare). Când scrieți scenarii, acest lucru poate fi o salvare. imprimă comenzile și parametrii acestora pe măsură ce sunt executate.
Vă oferă o formă rapidă de urmărire a execuției „aspră și gata”. Izolarea defectelor logice și identificarea erorilor devine mult, mult mai ușoară.
Vom adăuga opțiunea set -x la „script-8.sh”, o vom salva ca „script-10.sh” și o vom face executabilă.
#!/bin/bash set -euxo pipefail dacă [ -z "${New_Var:-}" ]; apoi echo "New_Var nu are nicio valoare atribuită." fi
Rulați-l pentru a vedea liniile de urmărire.
./script-10.sh
Identificarea erorilor în aceste exemple de scripturi banale este ușoară. Când începeți să scrieți scripturi mai implicate, aceste opțiuni își vor dovedi valoarea.