Hoe fouten in Bash-scripts op Linux te vangen

Hoe fouten in Bash-scripts op Linux te vangen
fatmawati achmad zaenuri/Shutterstock.com

Standaard rapporteert een Bash-script op Linux een fout, maar blijft het actief. We laten u zien hoe u zelf met fouten kunt omgaan, zodat u kunt beslissen wat er vervolgens moet gebeuren.

Foutafhandeling in scripts

Het afhandelen van fouten is onderdeel van programmeren. Zelfs als u foutloze code schrijft, kunt u nog steeds fouten tegenkomen. De omgeving op uw computer verandert in de loop van de tijd, terwijl u software installeert en verwijdert, mappen maakt en upgrades en updates uitvoert.

Parametervalidatiefouten aanpassen in PowerShell

VERWANTParametervalidatiefouten aanpassen in PowerShell

Een script dat vroeger probleemloos werd uitgevoerd, kan bijvoorbeeld in de problemen komen als de directorypaden veranderen of als de machtigingen voor een bestand worden gewijzigd. De standaardactie van de Bash-shell is om een ​​foutmelding af te drukken en door te gaan met het uitvoeren van het script. Dit is een gevaarlijke standaard.

Als de mislukte actie cruciaal is voor een andere verwerking of actie die later in uw script plaatsvindt, zal die kritieke actie niet slagen. Hoe rampzalig dat blijkt te zijn, hangt af van wat je script probeert te doen.

Een robuuster schema zou fouten detecteren en het script laten werken als het moet afsluiten of proberen de foutconditie te verhelpen. Als er bijvoorbeeld een map of bestand ontbreekt, kan het voldoende zijn om het script deze opnieuw te laten maken.

Als het script een probleem heeft ondervonden waarvan het niet kan worden hersteld, kan het worden afgesloten. Als het script moet worden afgesloten, kan het de kans krijgen om de vereiste opschoning uit te voeren, zoals het verwijderen van tijdelijke bestanden of het schrijven van de foutconditie en de reden van afsluiten naar een logbestand.

De uitgangsstatus detecteren

Opdrachten en programma’s genereren een waarde die naar het besturingssysteem wordt gestuurd wanneer ze worden beëindigd. Dit wordt hun exit-status genoemd. Het heeft de waarde nul als er geen fouten zijn, of een waarde die niet nul is als er een fout is opgetreden.

We kunnen de exit-status controleren – ook wel een retourcode genoemd – van de opdrachten die het script gebruikt en bepalen of de opdracht succesvol was of niet.

In Bash is nul gelijk aan waar. Als het antwoord van de opdracht iets anders is dan waar, weten we dat er een probleem is opgetreden en kunnen we passende maatregelen nemen.

Kopieer dit script naar een editor en sla het op in een bestand met de naam ‘bad_command.sh’.

#!/bin/bash

if ( ! bad_command ); then
  echo "bad_command flagged an error."
  exit 1
fi

U moet het script uitvoerbaar maken met de chmod opdracht. Dit is een stap die nodig is om elk script uitvoerbaar te maken, dus als u de scripts op uw eigen computer wilt uitproberen, vergeet dan niet om dit voor elk van hen te doen. Vervang in elk geval de naam van het juiste script.

chmod +x bad_command.sh

Een script uitvoerbaar maken met chmod

Wanneer we het script uitvoeren, zien we de verwachte foutmelding.

./bad_command.sh

De afsluitstatus van een opdracht controleren om te bepalen of er een fout is opgetreden

Er bestaat niet zo’n commando als “bad_command”, en het is ook niet de naam van een functie in het script. Het kan niet worden uitgevoerd, dus het antwoord is: niet nul. Als het antwoord niet nul is, wordt hier het uitroepteken gebruikt als de logische NOT operator – het lichaam van de if verklaring wordt uitgevoerd.

In een real-world script zou dit het script kunnen beëindigen, wat ons voorbeeld doet, of het zou kunnen proberen de foutconditie te verhelpen.

Het lijkt misschien op de exit 1 lijn is overbodig. Er staat tenslotte niets anders in het script en het zal hoe dan ook eindigen. Maar met behulp van de exit commando stelt ons in staat om een ​​exit-status terug te geven aan de shell. Als ons script ooit vanuit een tweede script wordt aangeroepen, weet dat tweede script dat er in dit script fouten zijn opgetreden.

U kunt gebruik maken van de logische OR operator met de exit-status van een commando, en roep een ander commando of een functie in je script aan als er een niet-nul antwoord is van het eerste commando.

command_1 || command_2

Dit werkt omdat ofwel het eerste commando wordt uitgevoerd OR de seconde. De meest linkse opdracht wordt als eerste uitgevoerd. Als het lukt, wordt het tweede commando niet uitgevoerd. Maar als de eerste opdracht mislukt, wordt de tweede opdracht uitgevoerd. Dus we kunnen de code zo structureren. Dit is “logische-or./sh.”

#!/bin/bash

error_handler()
{
  echo "Error: ($?) $1"
  exit 1
}

bad_command || error_handler "bad_command failed, Line: ${LINENO}"

We hebben een functie gedefinieerd met de naam error_handler . Dit drukt de exit-status af van de mislukte opdracht, vastgehouden in de variabele $? en een regel tekst die eraan wordt doorgegeven wanneer de functie wordt aangeroepen. Dit wordt vastgehouden in de variabele $1. De functie beëindigt het script met een afsluitstatus van één.

Het script probeert te draaien bad_command wat duidelijk faalt, dus het commando rechts van het logische OR exploitant, ||, is geëxecuteerd. Dit noemt de error_handler functie en geeft een tekenreeks door met de naam van de opdracht die is mislukt, en het regelnummer van de mislukte opdracht.

We voeren het script uit om het foutafhandelingsbericht te zien en controleren vervolgens de afsluitstatus van het script met echo.

./logical-or.sh
echo $?

De logische OR-operator gebruiken om de foutafhandelaar in een script aan te roepen

onze kleine error_handler functie geeft de exit-status van de poging om uit te voeren bad_command, de naam van de opdracht en het regelnummer. Dit is nuttige informatie wanneer u een script debugt.

De exit-status van het script is één. De 127 exit-status gerapporteerd door error_handler betekent “opdracht niet gevonden.” Als we wilden, zouden we dat kunnen gebruiken als de exit-status van het script door het door te geven aan de exit opdracht.

Een andere benadering zou zijn om uit te breiden error_handler om de verschillende mogelijke waarden van de exit-status te controleren en dienovereenkomstig verschillende acties uit te voeren, met behulp van dit type constructie:

exit_code=$?

if [ $exit_code -eq 1 ]; then
  echo "Operation not permitted"

elif [ $exit_code -eq 2 ]; then
  echo "Misuse of shell builtins"
.
.
.
elif [ $status -eq 128 ]; then
  echo "Invalid argument"
fi

Set gebruiken om een ​​exit te forceren

Als u weet dat u wilt dat uw script wordt afgesloten wanneer er een fout optreedt, kunt u het daartoe dwingen. het betekent dat je afziet van de kans op opschoning – of enige verdere schade ook – omdat je script wordt beëindigd zodra het een fout detecteert.

Gebruik hiervoor de set commando met de -e (fout) optie. Dit vertelt het script om af te sluiten wanneer een opdracht mislukt of retourneert een afsluitcode groter dan nul. Ook met behulp van de -E optie zorgt ervoor dat de foutdetectie en trapping werkt in shell-functies.

Hoe set en pipefail te gebruiken in Bash-scripts op Linux

VERWANTHoe set en pipefail te gebruiken in Bash-scripts op Linux

Om ook niet-geïnitialiseerde variabelen te vangen, voegt u de -u (uitgeschakeld) optie. Om ervoor te zorgen dat fouten in doorgesluisde reeksen worden gedetecteerd, voegt u de -o pipefail keuze. Zonder dit is de exit-status van een doorgesluisde reeks opdrachten de exit-status van de laatste commando in de volgorde. Een mislukte opdracht in het midden van de doorgesluisde reeks zou niet worden gedetecteerd. De -o pipefail optie moet in de lijst met opties staan.

De volgorde die u bovenaan uw script moet toevoegen, is:

set -Eeuo pipefail

Hier is een kort script genaamd “unset-var.sh”, met een unset-variabele erin.

#!/bin/bash

set -Eeou pipefail

echo "$unset_variable"

echo "Do we see this line?"

Wanneer we het script uitvoeren, wordt de unset_variable herkend als een niet-geïnitialiseerde variabele en wordt het script beëindigd.

./unset-var.sh

De opdracht set in een script gebruiken om het script te beëindigen als er een fout optreedt

De seconde echo opdracht wordt nooit uitgevoerd.

Trap gebruiken met fouten

Met het Bash trap-commando kun je een commando of een functie nomineren die moet worden aangeroepen wanneer een bepaald signaal wordt gegeven. Meestal wordt dit gebruikt om signalen op te vangen zoals: SIGINT die wordt verhoogd wanneer u op de toetsencombinatie Ctrl+C drukt. Dit script is “signint.sh.”

#!/bin/bash

trap "echo -e 'nTerminated by Ctrl+c'; exit" SIGINT

counter=0

while true
do 
  echo "Loop number:" $((++counter))
  sleep 1
done

De trap commando bevat een echo commando en de exit opdracht. Het wordt geactiveerd wanneer SIGINT wordt verhoogd. De rest van het script is een eenvoudige lus. Als u het script uitvoert en op Ctrl+C drukt, ziet u het bericht van de trap definitie, en het script wordt beëindigd.

./sigint.sh

Trap gebruiken in een script om Ctrl+c . te vangen

We kunnen gebruiken trap met de ERR signaal om fouten op te vangen zodra ze zich voordoen. Deze kunnen vervolgens worden ingevoerd in een commando of functie. Dit is “trap.sh.” We sturen foutmeldingen naar een functie genaamd error_handler.

#!/bin/bash

trap 'error_handler $? $LINENO' ERR

error_handler() {
  echo "Error: ($1) occurred on $2"
}

main() {
  echo "Inside main() function"
  bad_command
  second
  third
  exit $?
}

second() {
  echo "After call to main()"
  echo "Inside second() function"
}

third() {
  echo "Inside third() function"
}

main

Het grootste deel van het script bevindt zich in de main functie, die de . aanroept second en third functies. Wanneer er een fout wordt aangetroffen, in dit geval omdat bad_command bestaat niet – de trap instructie stuurt de fout naar de error_handler functie. Het geeft de exit-status van de mislukte opdracht en het regelnummer door aan de error_handler functie.

./trap.sh

Trap gebruiken met ERR om fouten in een script op te vangen

Ons error_handler functie geeft eenvoudig de details van de fout weer in het terminalvenster. Als je wilt, kun je een toevoegen exit commando toe aan de functie om het script te laten beëindigen. Of je zou een reeks van kunnen gebruiken if/elif/fi instructies om verschillende acties uit te voeren voor verschillende fouten.

Het is misschien mogelijk om sommige fouten te verhelpen, voor andere kan het nodig zijn dat het script stopt.

Een laatste tip

Fouten opvangen betekent vaak vooruitlopen op de dingen die fout kunnen gaan, en code invoeren om die eventualiteiten aan te pakken als ze zich voordoen. Dat is een aanvulling op het ervoor zorgen dat de uitvoeringsstroom en de interne logica van uw script correct zijn.

Als je deze opdracht gebruikt om je script uit te voeren, zal Bash je een traceeruitvoer laten zien terwijl het script wordt uitgevoerd:

bash -x your-script.sh

Bash schrijft de trace-uitvoer in het terminalvenster. Het toont elk commando met zijn argumenten – als het die heeft. Dit gebeurt nadat de commando’s zijn uitgevouwen, maar voordat ze worden uitgevoerd.

Het kan een enorme hulp zijn bij het opsporen van ongrijpbare bugs.

Nieuwste artikelen

Gerelateerde artikelen