Hoe de syntaxis van een Linux Bash-script te valideren voordat u het uitvoert?

Een Linux-terminal op het laptopscherm op een rode achtergrond.
fatmawati achmad zaenuri/Shutterstock

Bugs en typefouten in Linux Bash-scripts kunnen vervelende dingen doen wanneer het script wordt uitgevoerd. Hier zijn enkele manieren om de syntaxis van uw scripts te controleren voordat u ze zelfs maar uitvoert.

Die vervelende beestjes

Code schrijven is moeilijk. Of om nauwkeuriger te zijn, het schrijven van foutloze, niet-triviale code is moeilijk. En hoe meer regels code er in een programma of script zitten, hoe groter de kans dat er bugs in zitten.

De taal waarin u programmeert, heeft hier direct invloed op. Programmeren in assembly is veel moeilijker dan programmeren in C, en programmeren in C is uitdagender dan programmeren in Python. Hoe lager de taal waarin u programmeert, hoe meer werk u zelf moet doen. Python kan genieten van ingebouwde routines voor het verzamelen van afval, maar C en assembly zeker niet.

Wat is een

VERWANTWat is een ‘computerbug’ en waar komt de term vandaan?

Het schrijven van Linux-shellscripts brengt zijn eigen uitdagingen met zich mee. Met een gecompileerde taal zoals C, leest een programma dat een compiler wordt genoemd, uw broncode – de door mensen leesbare instructies die u in een tekstbestand typt – en transformeert het in een binair uitvoerbaar bestand. Het binaire bestand bevat de machinecode-instructies die de computer kan begrijpen en ernaar kan handelen.

De compiler genereert alleen een binair bestand als de broncode die hij leest en parseert, voldoet aan de syntaxis en andere regels van de taal. Als je a . spelt gereserveerd woord—een van de commandowoorden van de taal—of een onjuiste variabelenaam, de compiler zal een fout genereren.

Werken met variabelen in Bash

VERWANTWerken met variabelen in Bash

Sommige talen staan ​​er bijvoorbeeld op dat u een variabele declareert voordat u deze gebruikt, andere zijn niet zo kieskeurig. Als de taal waarin je werkt vereist dat je variabelen declareert, maar je vergeet dat te doen, zal de compiler een andere foutmelding geven. Hoe vervelend deze fouten tijdens het compileren ook zijn, ze vangen veel problemen op en dwingen je om ze aan te pakken. Maar zelfs als je een programma hebt dat geen syntactische fouten het betekent niet dat er geen bugs in zitten. Verre van.

Bugs die te wijten zijn aan logische fouten zijn meestal veel moeilijker te herkennen. Als je je programma vertelt om twee en drie op te tellen, maar je wilde echt dat het twee en twee optelde, krijg je niet het antwoord dat je verwachtte. Maar het programma doet waarvoor het is geschreven. Er is niets mis met de samenstelling of syntaxis van het programma. Het probleem ben jij. Je hebt een goed gevormd programma geschreven dat niet doet wat je wilde.

Testen is moeilijk

Het grondig testen van een programma, zelfs een eenvoudig programma, is tijdrovend. Een paar keer draaien is niet genoeg; je moet echt alle uitvoeringspaden in je code testen, zodat alle delen van de code worden geverifieerd. Als het programma om invoer vraagt, moet u een voldoende reeks invoerwaarden opgeven om alle voorwaarden te testen, inclusief onaanvaardbare invoer.

Voor talen op een hoger niveau helpen eenheidstests en geautomatiseerd testen om grondig testen een beheersbare oefening te maken. Dus de vraag is, zijn er tools die we kunnen gebruiken om ons te helpen bugvrije Bash-shellscripts te schrijven?

Het antwoord is ja, inclusief de Bash-shell zelf.

Bash gebruiken om de scriptsyntaxis te controleren

De bash -n (noexec) optie vertelt Bash om een ​​script te lezen en te controleren op syntactische fouten, zonder het script uit te voeren. Afhankelijk van waar je script voor bedoeld is, kan dit een stuk veiliger zijn dan het uitvoeren en op zoek gaan naar problemen.

Hier is het script dat we gaan controleren. Het is niet ingewikkeld, het is vooral een set van if verklaringen. Het vraagt ​​om en accepteert een getal dat een maand vertegenwoordigt. Het script bepaalt bij welk seizoen de maand hoort. Uiteraard werkt dit niet als de gebruiker helemaal geen invoer geeft, of als hij ongeldige invoer geeft, zoals een letter in plaats van een cijfer.

#! /bin/bash

read -p "Enter a month (1 to 12): " month

# did they enter anything?
if [ -z "$month" ]
then
  echo "You must enter a number representing a month."
  exit 1
fi

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); then
  echo "The month must be a number between 1 and 12."
  exit 0
fi

# is it a Spring month?
if (( "$month" >= 3 && "$month" < 6)); then
  echo "That's a Spring month."
  exit 0
fi

# is it a Summer month?
if (( "$month" >= 6 && "$month" < 9)); then
  echo "That's a Summer month."
  exit 0
fi

# is it an Autumn month?
if (( "$month" >= 9 && "$month" < 12)); then
  echo "That's an Autumn month."
  exit 0
fi

# it must be a Winter month
echo "That's a Winter month."
exit 0

In deze sectie wordt gecontroleerd of de gebruiker überhaupt iets heeft ingevoerd. Het test of de $month variabele is uitgeschakeld.

if [ -z "$month" ]
then
  echo "You must enter a number representing a month."
  exit 1
fi

In deze sectie wordt gecontroleerd of ze een getal tussen 1 en 12 hebben ingevoerd. Het vangt ook ongeldige invoer op die geen cijfer is, omdat letters en leestekens niet worden omgezet in numerieke waarden.

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); then
  echo "The month must be a number between 1 and 12."
  exit 0
fi

Alle andere If-clausules controleren of de waarde in de $month variabele ligt tussen twee waarden. Als dat zo is, hoort de maand bij dat seizoen. Als de door de gebruiker ingevoerde maand bijvoorbeeld 6, 7 of 8 is, is het een zomermaand.

# is it a Summer month?
if (( "$month" >= 6 && "$month" < 9)); then
  echo "That's a Summer month."
  exit 0
fi

Als je onze voorbeelden wilt doornemen, kopieer en plak je de tekst van het script in een editor en sla je het op als “seasons.sh”. Maak het script vervolgens uitvoerbaar met behulp van de chmod opdracht:

chmod +x seasons.sh

De uitvoerbare machtiging voor een script instellen

We kunnen het script testen door:

  • Helemaal geen input geven.
  • Het verstrekken van een niet-numerieke invoer.
  • Een numerieke waarde opgeven die buiten het bereik van 1 tot 12 ligt.
  • Geeft numerieke waarden binnen het bereik van 1 tot 12.

In alle gevallen starten we het script met hetzelfde commando. Het enige verschil is de invoer die de gebruiker levert wanneer deze door het script wordt gepromoot.

./seasons.sh

Een script testen met een verscheidenheid aan geldige en ongeldige invoer

Dat lijkt te werken zoals verwacht. Laten we Bash de syntaxis van ons script laten controleren. Dit doen we door een beroep te doen op de -n (noexec) optie en het doorgeven van de naam van ons script.

bash -n ./seasons.sh

Bash gebruiken om de syntaxis van een script te testen

Dit is een geval van “geen nieuws is goed nieuws”. Ons stil terugbrengen naar de opdrachtprompt is Bash’s manier om te zeggen dat alles in orde lijkt. Laten we ons script saboteren en een fout introduceren.

We verwijderen de then van de eerste if clausule.

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); # "then" has been removed
  echo "The month must be a number between 1 and 12."
  exit 0
fi

Laten we nu het script uitvoeren, eerst zonder en dan met invoer van de gebruiker.

./seasons.sh

Een script testen met ongeldige en geldige invoer

De eerste keer dat het script wordt uitgevoerd, voert de gebruiker geen waarde in en dus wordt het script beëindigd. Het gedeelte dat we hebben gesaboteerd wordt nooit bereikt. Het script eindigt zonder een foutmelding van Bash.

De tweede keer dat het script wordt uitgevoerd, geeft de gebruiker een invoerwaarde en de eerste if-clausule wordt uitgevoerd om de invoer van de gebruiker te controleren. Dat activeert de foutmelding van Bash.

Merk op dat Bash de syntaxis van die clausule controleert – en elke andere regel code – omdat het niet om de logica van het schrift. De gebruiker wordt niet gevraagd om een ​​getal in te voeren wanneer Bash het script controleert, omdat het script niet wordt uitgevoerd.

De verschillende mogelijke uitvoeringspaden van het script hebben geen invloed op hoe Bash de syntaxis controleert. Bash werkt eenvoudig en methodisch van de bovenkant van het script naar de onderkant en controleert de syntaxis voor elke regel.

Het ShellCheck-hulpprogramma

Een linter, genoemd naar een C-broncodecontroletool uit de hoogtijdagen van Unix, is een code-analysetool die wordt gebruikt om programmeerfouten, stilistische fouten en verdacht of twijfelachtig gebruik van de taal te detecteren. Linters zijn beschikbaar voor veel programmeertalen en staan ​​bekend als pedant. Niet alles wat een linter vindt is een bug per semaar alles wat ze onder uw aandacht brengen, verdient waarschijnlijk aandacht.

ShellCheck is een code-analysetool voor shellscripts. Het gedraagt ​​zich als een linter voor Bash.

Laten we onze vermiste opgeven then gereserveerd woord terug in ons script en probeer iets anders. We zullen de openingshaak “[“vanafhetallereerstebeginverwijderen[”fromtheveryfirstif clausule.

# did they enter anything?
if -z "$month" ] # opening bracket "[" removed
then
  echo "You must enter a number representing a month."
  exit 1
fi

als we Bash gebruiken om het script te controleren, wordt er geen probleem gevonden.

bash -n seasons.sh
./seasons.sh

Een foutmelding van een script dat de syntaxiscontrole heeft doorstaan ​​zonder gedetecteerde problemen

Maar wanneer we proberen om loop het script zien we een foutmelding. En ondanks de foutmelding blijft het script worden uitgevoerd. Dit is de reden waarom sommige bugs zo gevaarlijk zijn. Als de acties verderop in het script afhankelijk zijn van geldige invoer van de gebruiker, zal het gedrag van het script onvoorspelbaar zijn. Het kan mogelijk gegevens in gevaar brengen.

De reden dat de Bash -n (noexec) optie vindt de fout niet in het script is de openingshaak “[“iseenexternprogrammagenaamd[”isanexternalprogramcalled[. Het maakt geen deel uit van Bash. Het is een verkorte manier om de test opdracht.

Bash controleert het gebruik van externe programma’s niet wanneer het een script valideert.

ShellCheck installeren

ShellCheck vereist installatie. Om het op Ubuntu te installeren, typt u:

sudo apt install shellcheck

Shellcheck installeren op Ubuntu

Gebruik dit commando om ShellCheck op Fedora te installeren. Merk op dat de pakketnaam in hoofdletters is, maar wanneer u het commando in het terminalvenster geeft, is het allemaal in kleine letters.

sudo dnf install ShellCheck

Shellcheck installeren op Fedora

Op Manjaro en soortgelijke op Arch gebaseerde distributies gebruiken we pacman:

sudo pacman -S shellcheck

Shellcheck installeren op Manjaro

ShellCheck gebruiken

Laten we proberen ShellCheck op ons script uit te voeren.

shellcheck seasons.sh

Een script controleren met ShellCheck

ShellCheck vindt het probleem en rapporteert het aan ons, en biedt een reeks links voor meer informatie. Als u met de rechtermuisknop op een link klikt en “Link openen” kiest in het contextmenu dat verschijnt, wordt de link geopend in uw browser.

ShellCheck rapportage fouten en waarschuwingen

ShellCheck vindt ook een ander probleem, dat niet zo ernstig is. Het wordt gerapporteerd in groene tekst. Dit geeft aan dat het om een ​​waarschuwing gaat, niet om een ​​regelrechte fout.

Laten we onze fout corrigeren en de ontbrekende “[“Eenstrategievoorhetoplossenvanbugsisomeerstdeproblemenmetdehoogsteprioriteittecorrigerenenlaternaardeproblemenmeteenlagereprioriteitzoalswaarschuwingentoetewerken[”Onebug-fixstrategyistocorrectthehighestpriorityissuesfirstandworkdowntothelowerpriorityissueslikewarningslater

We hebben de ontbrekende “[“vervangenenShellChecknogmaalsuitgevoerd[”andranShellCheckoncemore

shellcheck seasons.sh

Een script een tweede keer controleren met ShellCheck

De enige output van ShellCheck verwijst naar onze vorige waarschuwing, dus dat is goed. We hebben geen problemen met hoge prioriteit die moeten worden opgelost.

De waarschuwing vertelt ons dat het gebruik van de read commando zonder de -r (lees zoals het is) optie zorgt ervoor dat eventuele backslashes in de invoer worden behandeld als escape-tekens. Dit is een goed voorbeeld van het soort pedante output dat een linter kan genereren. In ons geval zou de gebruiker sowieso geen backslash moeten invoeren – we hebben ze nodig om een ​​nummer in te voeren.

Waarschuwingen als deze vereisen een oordeel van de kant van de programmeur. De moeite nemen om het op te lossen, of het laten zoals het is? Het is een simpele oplossing van twee seconden. En het zal voorkomen dat de waarschuwing de uitvoer van ShellCheck overhoop haalt, dus we kunnen net zo goed zijn advies opvolgen. We voegen een “r” toe aan de optie voor de vlaggen op de read commando, en sla het script op.

read -pr "Enter a month (1 to 12): " month

Het nogmaals uitvoeren van ShellCheck geeft ons een schone gezondheidsverklaring.

Geen fouten of waarschuwingen gerapporteerd door ShellCheck

ShellCheck is je vriend

ShellCheck kan een heel scala aan problemen detecteren, rapporteren en adviseren. Bekijk hun galerij met slechte code, die laat zien hoeveel soorten problemen het kan detecteren.

Het is gratis, snel en het kost veel moeite om shellscripts te schrijven. Wat is er niet leuk aan?

Nieuwste artikelen

Gerelateerde artikelen