Wat betekent set -e in een bash-script?

Ik bestudeer de inhoud van dit preinst-bestand dat het script uitvoert voordat dat pakket wordt uitgepakt uit zijn Debian-archiefbestand (.deb).

Het script heeft de volgende code:

#!/bin/bash
set -e
# Automatically added by dh_installinit
if [ "$1" = install ]; then
   if [ -d /usr/share/MyApplicationName ]; then
     echo "MyApplicationName is just installed"
     return 1
   fi
   rm -Rf $HOME/.config/nautilus-actions/nautilus-actions.conf
   rm -Rf $HOME/.local/share/file-manager/actions/*
fi
# End automatically added section

Mijn eerste vraag gaat over de regel:

set -e

Ik denk dat de rest van het script vrij eenvoudig is: het controleert of de Debian/Ubuntu-pakketbeheerder een installatiebewerking uitvoert. Als dit het geval is, wordt gecontroleerd of mijn applicatie zojuist op het systeem is geïnstalleerd. Als dit het geval is, drukt het script het bericht “MijnApplicatienaam is zojuist geïnstalleerd”af en eindigt (return 1betekent dat eindigt op een “fout”, nietwaar?).

Als de gebruiker het Debian/Ubuntu-pakketsysteem vraagt om mijn pakket te installeren, verwijdert het script ook twee mappen.

Is dit juist of mis ik iets?


Antwoord 1, autoriteit 100%

Van help set:

 -e  Exit immediately if a command exits with a non-zero status.

Maar het wordt door sommigen als een slechte gewoonte beschouwd (auteurs van bash FAQ en irc freenode #bash FAQ). Het wordt aanbevolen om:

trap 'do_something' ERR

om de functie do_somethinguit te voeren wanneer er fouten optreden.

Zie http://mywiki.wooledge.org/BashFAQ/105


Antwoord 2, autoriteit 15%

set -estopt de uitvoering van een script als een opdracht of pijplijn een fout bevat – wat het tegenovergestelde is van het standaard shell-gedrag, namelijk het negeren van fouten in scripts. Typ help setin een terminal om de documentatie voor dit ingebouwde commando te zien.


Antwoord 3, autoriteit 8%

Ik vond dit bericht toen ik probeerde te achterhalen wat de exit-status was voor een script dat werd afgebroken vanwege een set -e. Het antwoord leek me niet voor de hand liggend; vandaar dit antwoord. Kortom, set -ebreekt de uitvoering van een opdracht af (bijvoorbeeld een shellscript) en retourneert de exit-statuscode van de opdracht die mislukt is (dwz het innerlijke script, niet het buitenste script).

Stel bijvoorbeeld dat ik het shellscript outer-test.shheb:

#!/bin/sh
set -e
./inner-test.sh
exit 62;

De code voor inner-test.shis:

#!/bin/sh
exit 26;

Als ik outer-script.shvanaf de opdrachtregel uitvoer, eindigt mijn outer-script met de exit-code van het inner-script:

$ ./outer-test.sh
$ echo $?
26

Antwoord 4, autoriteit 7%

Volgens bash – De ingebouwde sethandmatig, als -E/errexitis ingesteld, wordt de shell onmiddellijk afgesloten als een pijpleidingbestaande uit een enkele eenvoudige opdracht, een lijstof een samengesteld commandogeeft een niet-nul status terug.

Standaard is de exit-status van een pijplijn de exit-status van de laatste opdracht in de pijplijn, tenzij de optie pipefailis ingeschakeld (deze is standaard uitgeschakeld).

Zo ja, de retourstatus van de pijplijn van de laatste (meest rechtse) opdracht om af te sluiten met een status die niet nul is, of nul als alle opdrachten met succes worden afgesloten.

Als je iets bij het afsluiten wilt uitvoeren, probeer dan trapte definiëren, bijvoorbeeld:

trap onexit EXIT

waar onexituw functie is om iets te doen bij afsluiten, zoals hieronder, het afdrukken van de eenvoudige stapeltracering:

onexit(){ while caller $((n++)); do :; done; }

Er is een vergelijkbare optie -E/errtracedie zou in plaats daarvan op ERR vallen, bijv.:

trap onerr ERR

Voorbeelden

Voorbeeld nulstatus:

$ true; echo $?
0

Voorbeeld status niet-nul:

$ false; echo $?
1

Voorbeelden van negatiestatus:

$ ! false; echo $?
0
$ false || true; echo $?
0

Test met pipefailuitgeschakeld:

$ bash -c 'set +o pipefail -e; true | true | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; false | false | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; true | true | false; echo success'; echo $?
1

Test met pipefailingeschakeld:

$ bash -c 'set -o pipefail -e; true | false | true; echo success'; echo $?
1

Antwoord 5, autoriteit 2%

Dit is een oude vraag, maar geen van de antwoorden hier gaat over het gebruik van set -eook bekend als set -o errexitin scripts voor het afhandelen van pakketten van Debian. Het gebruik van deze optie is verplichtin deze scripts, volgens het Debian-beleid; de bedoeling is blijkbaar om elke mogelijkheid van een onverwerkte foutconditie te voorkomen.

Wat dit in de praktijk betekent, is dat je moet begrijpen onder welke omstandigheden de opdrachten die je uitvoert een fout kunnen retourneren, en dat je elk van die fouten expliciet moet afhandelen.

Veelvoorkomende problemen zijn b.v. diff(geeft een fout als er een verschil is) en grep(geeft een fout als er geen overeenkomst is). U kunt de fouten vermijden met expliciete behandeling:

diff this that ||
  echo "$0: there was a difference" >&2
grep cat food ||
  echo "$0: no cat in the food" >&2

(Let op Hoe we ervoor zorgen dat ze de naam van het huidige script opnemen in het bericht en het schrijven van diagnostische berichten op standaardfout in plaats van standaarduitvoer.)

Als er geen expliciete behandeling is, is echt nodig of nuttig, doet expliciet niets:

diff this that || true
grep cat food || :

(het gebruik van de Shell’s :No-op-opdracht is iets obscuur, maar redelijk algemeen gezien.)

Gewoon om te herhalen,

something || other

is steno voor

if something; then
    : nothing
else
    other
fi

d.w.z. We zeggen expliciet othermoeten worden uitgevoerd als en alleen als somethingmislukt. The Longhand if(en andere schelpstroombesturingsafschriften zoals while, until) ook een geldige manier is om een ​​fout te behandelen (inderdaad, als deze Werden niet, Shell-scripts met set -ekunnen nooit stroombesturingsafschriften bevatten!)

En ook, gewoon om expliciet te zijn, in de afwezigheid van een handler zoals deze, set -ezou ervoor zorgen dat het hele script onmiddellijk faalt met een fout als diffeen verschil gevonden, of als grepgeen match gevonden.

Aan de andere kant produceren sommige commando’s geen exit-foutstatus wanneer u dat zou willen. Vaak problematische commando’s zijn find(exit-status geeft niet aan of bestanden daadwerkelijk zijn gevonden) en sed(exit-status geeft niet aan of het script invoer heeft ontvangen of daadwerkelijk heeft uitgevoerd opdrachten succesvol uitgevoerd). Een eenvoudige bewaker in sommige scenario’s is om naar een commando te pipen dat wel schreeuwt als er geen uitvoer is:

find things | grep .
sed -e 's/o/me/' stuff | grep ^

Opgemerkt moet worden dat de exit-status van een pijplijn de exit-status is van de laatste opdracht in die pijplijn. Dus de bovenstaande commando’s maskeren eigenlijk volledig de status van finden sed, en vertellen je alleen of grepuiteindelijk gelukt is.

(Bash heeft natuurlijk set -o pipefail; maar Debian-pakketscripts kunnen geen Bash-functies gebruiken. Het beleid dicteert duidelijk het gebruik van POSIX shvoor deze scripts , hoewel dit niet altijd het geval was.)

In veel situaties is dit iets om apart op te letten bij defensief coderen. Soms moet je b.v. ga door een tijdelijk bestand zodat je kunt zien of de opdracht die die uitvoer produceerde, met succes is voltooid, zelfs als idioom en gemak je anders zouden sturen om een shell-pijplijn te gebruiken.


6

Script 1: without setting -e
#!/bin/bash
decho "hi"
echo "hello"
This will throw error in decho and program continuous to next line
Script 2: With setting -e
#!/bin/bash
set -e
decho "hi" 
echo "hello"
# Up to decho "hi" shell will process and program exit, it will not proceed further

7

cat a.sh
#! /bin/bash
#going forward report subshell or command exit value if errors
#set -e
(cat b.txt)
echo "hi"
./a.sh; echo $?
cat: b.txt: No such file or directory
hi
0

Met SET -E heeft gereageerd dat we zien dat ECHO “HI” exit-status wordt gemeld en hi is afgedrukt.

cat a.sh
#! /bin/bash
#going forward report subshell or command exit value if errors
set -e
(cat b.txt)
echo "hi"
./a.sh; echo $?
cat: b.txt: No such file or directory
1

Nu zien we B.TXT-fout die in plaats daarvan wordt gemeld en geen hallo afgedrukt.

Dus standaard gedrag van Shell Script is om opdrachtfouten te negeren en door te gaan met de verwerking en rapport van de laatste opdracht. Als u nogmaals wilt afsluiten en de status wilt melden, kunnen wij -e-optie gebruiken.

Other episodes