Cum să validați sintaxa unui script Linux Bash înainte de a-l rula

Publicat: 2022-06-16
Un terminal Linux pe ecranul laptopului pe un fundal roșu.
fatmawati achmad zaenuri/Shutterstock

Erori și greșeli de tipar în scripturile Linux Bash pot face lucruri groaznice atunci când scriptul este rulat. Iată câteva modalități de a verifica sintaxa scripturilor înainte de a le rula.

Acei insecte plictisitoare

Scrierea codului este greu. Sau, pentru a fi mai precis, scrierea unui cod non-trivial fără erori este dificilă. Și cu cât există mai multe linii de cod într-un program sau script, cu atât este mai probabil să existe erori în el.

Limba în care programați are o legătură directă cu acest lucru. Programarea în asamblare este mult mai dificilă decât programarea în C, iar programarea în C este mai dificilă decât programarea în Python. Cu cât limbajul în care programați este mai scăzut, cu atât mai multă muncă trebuie să vă faceți. Python s-ar putea bucura de rutinele de colectare a gunoiului încorporate, dar C și asamblarea cu siguranță nu.

Ce este un „error de calculator” și de unde a venit termenul?
LEGATE Ce este o „eroare de computer” și de unde a venit termenul?

Scrierea de scripturi shell Linux pune propriile provocări. Cu un limbaj compilat precum C, un program numit compilator îți citește codul sursă - instrucțiunile care pot fi citite de oameni pe care le tastezi într-un fișier text - și îl transformă într-un fișier executabil binar. Fișierul binar conține instrucțiunile codului mașinii pe care computerul le poate înțelege și pe care le poate acționa.

Compilatorul va genera un fișier binar numai dacă codul sursă pe care îl citește și îl analizează respectă sintaxa și alte reguli ale limbajului. Dacă scrieți incorect un cuvânt rezervat - unul dintre cuvintele de comandă ale limbajului - sau un nume de variabilă, compilatorul va arunca o eroare.

Cum se lucrează cu variabile în Bash
LEGATE Cum să lucrați cu variabile în Bash

De exemplu, unele limbi insistă să declarați o variabilă înainte de a o folosi, altele nu sunt atât de exigente. Dacă limbajul în care lucrați vă cere să declarați variabile, dar uitați să faceți asta, compilatorul va afișa un alt mesaj de eroare. Oricât de enervante sunt aceste erori de compilare, ele prind o mulțime de probleme și te obligă să le rezolvi. Dar chiar și atunci când aveți un program care nu are erori sintactice , nu înseamnă că nu există erori în el. Departe de.

Publicitate

Bug-urile care se datorează unor defecte logice sunt de obicei mult mai greu de detectat. Dacă îi spui programului tău să adauge doi și trei, dar chiar ai vrut să adauge doi și doi, nu vei primi răspunsul la care te așteptai. Dar programul face ceea ce a fost scris pentru a face. Nu este nimic în neregulă cu compoziția sau sintaxa programului. Problema esti tu. Ai scris un program bine format care nu face ceea ce ai vrut.

Testarea este dificilă

Testarea temeinică a unui program, chiar și a unuia simplu, necesită timp. Rularea acestuia de câteva ori nu este suficient; chiar trebuie să testați toate căile de execuție din codul dvs., astfel încât toate părțile codului să fie verificate. Dacă programul solicită introducerea, trebuie să furnizați o gamă suficientă de valori de intrare pentru a testa toate condițiile, inclusiv intrările inacceptabile.

Pentru limbile de nivel superior, testele unitare și testarea automată contribuie la transformarea testării amănunțite într-un exercițiu ușor de gestionat. Deci întrebarea este, există instrumente pe care le putem folosi pentru a ne ajuta să scriem scripturi shell Bash fără erori?

Răspunsul este da, inclusiv shell-ul Bash în sine.

Folosind Bash pentru a verifica sintaxa scriptului

Opțiunea Bash -n (noexec) îi spune lui Bash să citească un script și să-l verifice pentru erori sintactice, fără a rula scriptul. În funcție de ceea ce este intenționat să facă scriptul dvs., acest lucru poate fi mult mai sigur decât să îl rulați și să căutați probleme.

Iată scriptul pe care îl vom verifica. Nu este complicat, este în principal un set de declarații if . Acesta solicită și acceptă un număr reprezentând o lună. Scenariul decide cărui anotimp îi aparține luna. Evident, acest lucru nu va funcționa dacă utilizatorul nu furnizează nicio intrare sau dacă furnizează o introducere nevalidă, cum ar fi o literă în loc de o cifră.

 #! /bin/bash

citiți -p „Introduceți o lună (de la 1 la 12): „ lună

# au introdus ceva?
dacă [-z „$lună”]
apoi
  echo „Trebuie să introduceți un număr reprezentând o lună”.
  iesirea 1
fi

# este o lună valabilă?
dacă (( „$lună” < 1 || „$lună” > 12)); apoi
  echo „Luna trebuie să fie un număr între 1 și 12.”
  iesirea 0
fi

# este o lună de primăvară?
if (( "$lună" >= 3 && "$lună" < 6)); apoi
  echo „Aceasta este o lună de primăvară”.
  iesirea 0
fi

# este o lună de vară?
if (( "$lună" >= 6 && "$lună" < 9)); apoi
  echo „Aceasta este o lună de vară”.
  iesirea 0
fi

# este o lună de toamnă?
if (( "$lună" >= 9 && "$lună" < 12)); apoi
  echo „Aceasta este o lună de toamnă”.
  iesirea 0
fi

# trebuie să fie o lună de iarnă
echo „Aceasta este o lună de iarnă”.
iesirea 0
Publicitate

Această secțiune verifică dacă utilizatorul a introdus ceva. Testează dacă variabila $month este nesetată.

 dacă [-z „$lună”]
apoi
  echo „Trebuie să introduceți un număr reprezentând o lună”.
  iesirea 1
fi

Această secțiune verifică dacă au introdus un număr între 1 și 12. De asemenea, captează introducerea nevalidă care nu este o cifră, deoarece literele și simbolurile de punctuație nu se traduc în valori numerice.

 # este o lună valabilă?
dacă (( „$lună” < 1 || „$lună” > 12)); apoi
  echo „Luna trebuie să fie un număr între 1 și 12.”
  iesirea 0
fi

Toate celelalte clauze If verifică dacă valoarea din variabila $month este între două valori. Dacă este, luna aparține acelui anotimp. De exemplu, dacă luna introdusă de utilizator este 6, 7 sau 8, este o lună de vară.

 # este o lună de vară?
if (( "$lună" >= 6 && "$lună" < 9)); apoi
  echo „Aceasta este o lună de vară”.
  iesirea 0
fi

Dacă doriți să lucrați prin exemplele noastre, copiați și inserați textul scriptului într-un editor și salvați-l ca „seasons.sh”. Apoi faceți scriptul executabil utilizând comanda chmod :

 chmod +x anotimpuri.sh 
Setarea permisiunii executabile pentru un script

Putem testa scriptul prin

  • Nu oferă nicio intrare.
  • Furnizarea unei intrări non-numerice.
  • Furnizarea unei valori numerice care se află în afara intervalului de la 1 la 12.
  • Furnizarea de valori numerice în intervalul de la 1 la 12.

În toate cazurile, începem scriptul cu aceeași comandă. Singura diferență este intrarea pe care utilizatorul o oferă atunci când este promovată de script.

 ./sezonuri.sh 

Testarea unui script cu o varietate de intrări valide și nevalide

Se pare că funcționează conform așteptărilor. Să-l punem pe Bash să verifice sintaxa scriptului nostru. Facem acest lucru invocând opțiunea -n (noexec) și trecând numele scriptului nostru.

 bash -n ./seasons.sh 

Folosind Bash pentru a testa sintaxa unui script

Publicitate

Acesta este un caz de „nici o veste nu este o veste bună”. Revenirea în tăcere la promptul de comandă este modul lui Bash de a spune că totul pare OK. Să ne sabotăm scriptul și să introducem o eroare.

Vom elimina then din prima clauză if .

 # este o lună valabilă?
dacă (( „$lună” < 1 || „$lună” > 12)); # „atunci” a fost eliminat
  echo „Luna trebuie să fie un număr între 1 și 12.”
  iesirea 0
fi

Acum să rulăm scriptul, mai întâi fără și apoi cu intrare de la utilizator.

 ./sezonuri.sh 

Testarea unui script cu intrări invalide și valide

Prima dată când scriptul este rulat, utilizatorul nu introduce o valoare și astfel scriptul se termină. Secțiunea pe care am sabotat-o ​​nu se ajunge niciodată. Scriptul se termină fără un mesaj de eroare de la Bash.

A doua oară când scriptul este rulat, utilizatorul furnizează o valoare de intrare, iar prima clauză if este executată pentru a verifica corect intrarea utilizatorului. Asta declanșează mesajul de eroare de la Bash.

Rețineți că Bash verifică sintaxa acelei clauze – și orice altă linie de cod – pentru că nu îi pasă de logica scriptului. Utilizatorului nu i se solicită să introducă un număr atunci când Bash verifică scriptul, deoarece scriptul nu rulează.

Diferitele căi posibile de execuție ale scriptului nu afectează modul în care Bash verifică sintaxa. Bash lucrează simplu și metodic din partea de sus a scriptului până în jos, verificând sintaxa pentru fiecare linie.

Utilitarul ShellCheck

Un linter - numit după un instrument de verificare a codului sursă C din perioada de glorie a Unix - este un instrument de analiză a codului folosit pentru a detecta erorile de programare, erorile stilistice și utilizarea suspectă sau îndoielnică a limbajului. Linters sunt disponibile pentru multe limbaje de programare și sunt renumite pentru că sunt pedante. Nu tot ce găsește un linter este un bug în sine , dar orice vă aduce la cunoștință probabil merită atenție.

Publicitate

ShellCheck este un instrument de analiză a codului pentru scripturile shell. Se comportă ca un linter pentru Bash.

Să punem din nou cuvântul care lipsește then rezervat în scenariul nostru și să încercăm altceva. Vom elimina paranteza de deschidere „[” chiar din prima clauză if .

 # au introdus ceva?
if -z "$lună" ] # paranteza de deschidere "[" eliminată
apoi
  echo „Trebuie să introduceți un număr reprezentând o lună”.
  iesirea 1
fi

dacă folosim Bash pentru a verifica scriptul, nu găsește nicio problemă.

 bash -n anotimpuri.sh
 ./sezonuri.sh 

Un mesaj de eroare de la un script care a trecut de verificarea sintaxei fără probleme detectate

Dar când încercăm să rulăm scriptul, vedem un mesaj de eroare. Și, în ciuda mesajului de eroare, scriptul continuă să se execute. Acesta este motivul pentru care unele bug-uri sunt atât de periculoase. Dacă acțiunile întreprinse mai departe în script se bazează pe o intrare validă din partea utilizatorului, comportamentul scriptului va fi imprevizibil. Ar putea pune în pericol datele.

Motivul pentru care opțiunea Bash -n (noexec) nu găsește eroarea în script este paranteza de deschidere „[” este un program extern numit [ . Nu face parte din Bash. Este o modalitate scurtă de utilizare a comenzii de test .

Publicitate

Bash nu verifică utilizarea programelor externe atunci când validează un script.

Instalarea ShellCheck

ShellCheck necesită instalare. Pentru a-l instala pe Ubuntu, tastați:

 sudo apt install shellcheck 

Instalarea shellcheck pe Ubuntu

Pentru a instala ShellCheck pe Fedora, utilizați această comandă. Rețineți că numele pachetului este mixt cu majuscule, dar când lansați comanda în fereastra terminalului, totul este cu litere mici.

 sudo dnf instalează ShellCheck 

Instalarea shellcheck pe Fedora

Pe Manjaro și distribuții similare bazate pe Arch, folosim pacman :

 sudo pacman -S shellcheck 

Se instalează shellcheck pe Manjaro

Folosind ShellCheck

Să încercăm să rulăm ShellCheck pe scriptul nostru.

 shellcheck anotimpuri.sh 

Verificarea unui script cu ShellCheck

ShellCheck găsește problema și ne-o raportează și oferă un set de link-uri pentru informații suplimentare. Dacă faceți clic dreapta pe un link și alegeți „Open Link” din meniul contextual care apare, linkul se va deschide în browser.

ShellCheck raportează erori și avertismente

ShellCheck găsește și o altă problemă, care nu este la fel de gravă. Este raportat în text verde. Aceasta indică că este un avertisment, nu o eroare totală.

Să ne corectăm eroarea și să înlocuim „[.” lipsă. O strategie de remediere a erorilor este de a corecta mai întâi problemele cu cea mai mare prioritate și de a reduce mai târziu problemele de prioritate inferioară, cum ar fi avertismentele.

Am înlocuit „[” lipsă și am rulat ShellCheck încă o dată.

 shellcheck anotimpuri.sh 

Verificarea unui script a doua oară cu ShellCheck

Publicitate

Singura ieșire de la ShellCheck se referă la avertismentul nostru anterior, așa că este bine. Nu avem probleme cu prioritate ridicată care să necesite remediere.

Avertismentul ne spune că utilizarea comenzii de read fără opțiunea -r (citește așa cum este) va face ca orice bară oblică inversă din intrare să fie tratată ca caractere de escape. Acesta este un bun exemplu al tipului de ieșire pedante pe care o poate genera un linter. În cazul nostru, utilizatorul nu ar trebui să introducă o bară oblică inversă - avem nevoie de el să introducă un număr.

Avertismente ca acesta necesită un apel de judecată din partea programatorului. Depuneți eforturi pentru a o repara sau lăsați-o așa cum este? Este o soluție simplă de două secunde. Și va opri avertismentul care aglomera ieșirea ShellCheck, așa că am putea la fel de bine să luăm sfatul acestuia. Vom adăuga un „r” pentru a opționa steagurile de pe comanda de read și vom salva scriptul.

 citiți -pr „Introduceți o lună (de la 1 la 12): „ lună

Rularea ShellCheck încă o dată ne oferă o stare de sănătate curată.

Nu există erori sau avertismente raportate de ShellCheck

ShellCheck este prietenul tău

ShellCheck poate detecta, raporta și consilia cu privire la o serie întreagă de probleme. Consultați galeria lor de coduri greșite, care arată câte tipuri de probleme poate detecta.

Este gratuit, rapid și elimină multă durere din scrierea scripturilor shell. Ce nu e de placut?