Hoe kan ik in een Bash-script het hele script afsluiten als een bepaalde voorwaarde zich voordoet?

Ik schrijf een script in Bash om wat code te testen. Het lijkt echter dwaas om de tests uit te voeren als het compileren van de code in de eerste plaats mislukt, in welk geval ik de tests gewoon afbreek.

Is er een manier waarop ik dit kan doen zonder het hele script in een while-lus te stoppen en pauzes te gebruiken? Iets als een dun dun dungoto?


Antwoord 1, autoriteit 100%

Probeer deze verklaring:

exit 1

Vervang 1door de juiste foutcodes. Zie ook Afsluitcodes met speciale betekenis.


Antwoord 2, autoriteit 79%

Gebruik set -e

#!/bin/bash
set -e
/bin/command-that-fails
/bin/command-that-fails2

Het script wordt beëindigd na de eerste regel die mislukt (retourneert een afsluitcode die niet nul is). In dit geval wordt command-that-fails2niet uitgevoerd.

Als u de retourstatus van elk afzonderlijk commando zou controleren, zou uw script er als volgt uitzien:

#!/bin/bash
# I'm assuming you're using make
cd /project-dir
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi
cd /project-dir2
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi

Met set -ezou het er als volgt uitzien:

#!/bin/bash
set -e
cd /project-dir
make
cd /project-dir2
make

Elke opdracht die faalt, zal ervoor zorgen dat het hele script mislukt en een exit-status retourneert die u kunt controleren met $?. Als je script erg lang is of als je veel dingen aan het bouwen bent, wordt het behoorlijk lelijk als je overal retourstatuscontroles toevoegt.


Antwoord 3, autoriteit 29%

Een SysOps-man leerde me ooit de Three-Fingered Claw-techniek:

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }

Deze functies zijn *NIX OS en shell-smaakrobuust. Zet ze aan het begin van je script (bash of anderszins), try()je statement en code aan.

Uitleg

(gebaseerd op vliegende schapenopmerking).

  • yell: print de scriptnaam en alle argumenten naar stderr:
    • $0is het pad naar het script ;
    • $*zijn allemaal argumenten.
    • >&2betekent dat >stdout omleidt naar & pipe 2. pipe 1zou stdoutzelf zijn.
  • diedoet hetzelfde als yell, maar sluit af met een niet-0 exit-status, wat ‘mislukt’ betekent.
  • trygebruikt de ||(boolean OR), die alleen de rechterkant evalueert als de linkerkant mislukt.
    • $@zijn weer allemaal argumenten, maar anders.

Antwoord 4, autoriteit 4%

Als u het script aanroept met source, kunt u return <x>gebruiken waarbij <x>het script is exit-status (gebruik een waarde die niet nul is voor fout of onwaar). Maar als u een uitvoerbaar script aanroept (d.w.z. rechtstreeks met zijn bestandsnaam), zal de return-instructie resulteren in een klacht (foutmelding “return: can only `return’ from a function of sourced script”).

Als in plaats daarvan exit <x>wordt gebruikt en het script wordt aangeroepen met source, zal dit resulteren in het verlaten van de shell waarmee het script is gestart, maar een uitvoerbaar bestand script wordt gewoon beëindigd, zoals verwacht.

Om beide gevallen in hetzelfde script af te handelen, kunt u

return <x> 2> /dev/null || exit <x>

Dit zal elke aanroep afhandelen die geschikt is. Dat veronderstelt dat u deze verklaring op het hoogste niveau van het script zult gebruiken. Ik raad af om het script rechtstreeks vanuit een functie te verlaten.

Opmerking: <x>zou slechts een getal moeten zijn.


Antwoord 5, autoriteit 2%

Ik gebruik vaak een functie genaamd run() om fouten af te handelen. Elke aanroep die ik wil doen, wordt doorgegeven aan deze functie, zodat het hele script wordt afgesloten wanneer er een fout optreedt. Het voordeel hiervan ten opzichte van de set -e-oplossing is dat het script niet stil wordt afgesloten wanneer een regel faalt, en u kan vertellen wat het probleem is. In het volgende voorbeeld wordt de 3e regel niet uitgevoerd omdat het script eindigt bij de aanroep naar false.

function run() {
  cmd_output=$(eval $1)
  return_value=$?
  if [ $return_value != 0 ]; then
    echo "Command $1 failed"
    exit -1
  else
    echo "output: $cmd_output"
    echo "Command succeeded."
  fi
  return $return_value
}
run "date"
run "false"
run "date"

6

Ik heb dezelfde vraag, maar kan het niet vragen omdat het een duplicaat zou zijn.

Het geaccepteerde antwoord, met uitgang, werkt niet wanneer het script een beetje ingewikkelder is. Als u een achtergrondproces gebruikt om te controleren op de voorwaarde, verlaat u alleen dat proces, omdat deze in een subschaal werkt. Om het script te doden, moet je het expliciet doden (dat is tenminste de enige manier waarop ik weet).

Hier is een klein script over hoe het te doen:

#!/bin/bash
boom() {
    while true; do sleep 1.2; echo boom; done
}
f() {
    echo Hello
    N=0
    while
        ((N++ <10))
    do
        sleep 1
        echo $N
        #        ((N > 5)) && exit 4 # does not work
        ((N > 5)) && { kill -9 $$; exit 5; } # works 
    done
}
boom &
f &
while true; do sleep 0.5; echo beep; done

Dit is een beter antwoord, maar nog steeds onvolledig A Ik weet echt niet hoe ik de -onderdelen kwijt ben.


7

U kunt uw programma sluiten op programmanaam op volgwijze:

voor soft-exit do

pkill -9 -x programname # Replace "programmname" by your programme

voor harde exit do

pkill -15 -x programname # Replace "programmname" by your programme

Als u wilt weten hoe u de voorwaarde wilt evalueren voor het sluiten van een programma, moet u uw vraag aanpassen.


8

U kunt uw programma sluiten met PID van programma op volgwijze:

voor soft-exit do

kill -9 $PID # Replace "programmname" by your programme

voor harde exit do

kill -15 $PID # Replace "programmname" by your programme

Als u wilt weten hoe u de voorwaarde wilt evalueren voor het sluiten van een programma, moet u uw vraag aanpassen.

Other episodes