Vraag Wat doet 'set-e', en waarom zou het als gevaarlijk kunnen worden beschouwd?


Deze vraag is verschenen in een pre-interview quiz en ik word er gek van. Kan iemand dit beantwoorden en mij op mijn gemak stellen? De quiz heeft geen verwijzing naar een bepaalde shell, maar de taakomschrijving is voor een unix sa. nogmaals, de vraag is gewoon ...

Wat doet 'set-e', en waarom zou het als gevaarlijk kunnen worden beschouwd?


141
2018-05-19 16:39


oorsprong


Hier is een gerelateerde thread: stackoverflow.com/questions/64786/error-handling-in-bash/... - Stefan Lasiewski


antwoorden:


set -e zorgt ervoor dat de shell wordt afgesloten als een subopdracht of pijplijn een niet-nulstatus retourneert.

Het antwoord waar de interviewer waarschijnlijk naar op zoek was, is:

Het zou gevaarlijk zijn om "set-e" te gebruiken bij het maken van init.d scripts:

Van http://www.debian.org/doc/debian-policy/ch-opersys.html 9.3.2 -

Wees voorzichtig met het gebruik van set -e in init.d-scripts. Het schrijven van correcte init.d-scripts vereist het accepteren van verschillende foutuitgangsstatussen wanneer daemons al actief zijn of al gestopt zijn zonder het init.d-script af te breken, en algemene init.d-functiebibliotheken zijn niet veilig om te bellen met set -e in effect. Voor init.d-scripts is het vaak gemakkelijker om set -e niet te gebruiken en in plaats daarvan het resultaat van elke opdracht afzonderlijk te controleren.

Dit is een geldige vraag vanuit het oogpunt van een interviewer, omdat het de kandidaten meet aan de hand van kennis van server-level scripting en automatisering


146
2017-08-09 21:01



leuke vondst. Bedankt. - egorgry
goed punt. het zou het opstartproces stoppen voor iets dat technisch mogelijk een fout zou zijn, maar niet zou moeten zorgen dat het hele script stopt - Matt
Hoewel ik het daarmee eens ben stackoverflow.com/questions/78497/..., Ik denk dat deze stijl een goede fit vindt met bash voor korte initcontroles en logging of andere omgevingsap patchen op de aarde voordat de doelworkload wordt uitgevoerd. We gebruiken ditzelfde beleid voor onze docker image init scripts. - joshperry


Van bash(1):

          -e      Exit immediately if a pipeline (which may consist  of  a
                  single  simple command),  a subshell command enclosed in
                  parentheses, or one of the commands executed as part  of
                  a  command  list  enclosed  by braces (see SHELL GRAMMAR
                  above) exits with a non-zero status.  The shell does not
                  exit  if  the  command that fails is part of the command
                  list immediately following a  while  or  until  keyword,
                  part  of  the  test  following  the  if or elif reserved
                  words, part of any command executed in a && or  ││  list
                  except  the  command  following  the final && or ││, any
                  command in a pipeline but the last, or if the  command’s
                  return  value  is being inverted with !.  A trap on ERR,
                  if set, is executed before the shell exits.  This option
                  applies to the shell environment and each subshell envi-
                  ronment separately (see  COMMAND  EXECUTION  ENVIRONMENT
                  above), and may cause subshells to exit before executing
                  all the commands in the subshell.

Helaas ben ik niet creatief genoeg om erover na te denken waarom het gevaarlijk zou zijn, anders dan dat "de rest van het script niet wordt uitgevoerd" of "misschien echte problemen maskeert".


33
2018-05-19 16:43



echte / andere problemen maskeren, ja, ik denk dat ik dat kon zien ... ik worstelde om een ​​voorbeeld te bedenken dat het gevaarlijk was, en ook ... - cpbills
Daar is de manpage voor set! Ik kom er altijd op uit builtin(1). Bedankt. - Jared Beck
hoe zou ik weten dat de documentatie voor set is om mee om te gaan man 1 bash?? en hoe zou iemand de -e optie voor de set sleutelwoord in een handboekpagina die zo enorm groot is? je kan niet gewoon /-e zoek hier - Blauhirn
@Blauhirn gebruiken help set - Blauhirn


het zou genoteerd moeten worden dat set -e kan worden in- en uitgeschakeld voor verschillende secties van een script. Het hoeft niet aan te staan ​​voor de uitvoering van het hele script. Het kan zelfs voorwaardelijk worden ingeschakeld. Dat gezegd hebbende, ik gebruik het nooit, omdat ik mijn eigen fouten afhandel (of niet).

some code
set -e     # same as set -o errexit
more code  # exit on non-zero status
set +e     # same as set +o errexit
more code  # no exit on non-zero status

Ook opmerkelijk is dit van de Bash man pagina sectie op de trap commando dat ook beschrijft hoe set -e functies onder bepaalde omstandigheden.

De                 ERR-trap wordt niet uitgevoerd als de mislukte opdracht deel uitmaakt van de                 lijst met opdrachten onmiddellijk na een tijdje of tot trefwoord,                 deel van de test in een if-statement, onderdeel van een uitgevoerde opdracht                 in een && of ⎪⎪ lijst, of als de retourwaarde van de opdracht is                 omgekeerd via! Dit zijn dezelfde voorwaarden gehoorzaamd door de                 errexit optie.

Er zijn dus enkele omstandigheden waaronder een niet-nul status geen exit zal veroorzaken.

Ik denk dat het gevaar is om niet te begrijpen wanneer set -e komt in het spel en wanneer dat niet het geval is en vertrouwt het op een verkeerde manier onder een ongeldige veronderstelling.

Zie ook alstublieft BashFAQ / 105 Waarom doe ik niet -e (of stel -o errexit, of trap ERR) in wat ik verwachtte?


19
2018-05-19 22:39



Afwijkend van de vraag een beetje, is dit antwoord precies wat ik zoek: het uitzetten voor slechts een klein deel van een script! - Stephan Bijzitter


Houd in gedachten dat dit een quiz is voor een sollicitatiegesprek. De vragen zijn mogelijk geschreven door de huidige staf en ze kunnen verkeerd zijn. Dit is niet per se slecht, en iedereen maakt fouten, en interviewvragen zitten vaak zonder nadenken in een donkere hoek en komen alleen uit tijdens een interview.

Het is heel goed mogelijk dat 'set -e' niets doet dat we als 'gevaarlijk' zouden beschouwen. Maar de auteur van die vraag kan ten onrechte geloven dat 'set-e' gevaarlijk is, vanwege hun eigen onwetendheid of vooroordelen. Misschien hebben ze een shell-script met fouten geschreven, het heeft vreselijk gebombardeerd en ze dachten ten onrechte dat 'set-e' de schuld was, terwijl ze in feite nalieten een goede foutcontrole te schrijven.

Ik heb de afgelopen twee jaar deelgenomen aan waarschijnlijk 40 sollicitatiegesprekken, en de interviewers stellen soms vragen die verkeerd zijn, of antwoorden die niet kloppen.

Of misschien is het een strikvraag, die kreupel zou zijn, maar niet geheel onverwacht.

Of misschien is dit een goede verklaring: http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg473314.html


13
2018-05-19 17:03



+1 Ik zit in dezelfde boot en veel van de 'technische' interviews waarmee ik te maken heb gehad zijn op zijn minst enigszins misplaatst. - cpbills
Wauw. Goede vondst op de Debian-lijst. +1 voor de onwetendheid van interviewvragen. Ik herinner me dat ik ooit een netback-antwoord had omdat ik er 100% zeker van was dat ik gelijk had. Ze zeiden nee. Ik ging naar huis en googelde het, ik had gelijk. - egorgry


set -e vertelt bash, in een script, om af te sluiten als iets een niet-nul-retourwaarde retourneert.

ik kon zien hoe dat vervelend zou zijn, en buggy, niet zeker van gevaarlijk, tenzij je permissies had geopend voor iets, en voordat je ze weer kon beperken, stierf je script.


9
2018-05-19 16:46



Dat is interessant. Ik dacht niet aan toestemmingen die werden geopend in een script dat voortijdig overlijdt, maar ik kon dat als gevaarlijk beschouwen. Het leuke aan deze quiz is dat je geen referentiemateriaal zoals man of google kunt gebruiken en als je niet volledig kunt antwoorden, neem je het helemaal niet op. - egorgry
dat is gewoon stom, ik zou deze werkgever heroverwegen ... grapje (soort van). het is goed om een ​​sterke basis van kennis te hebben, maar de helft van het IT-werk is weten / waar / om de informatie te vinden ... hopelijk waren ze slim genoeg om hiermee rekening te houden bij het scoren van sollicitanten. in een kanttekening, ik zie / nee / gebruiken voor set -ein feite spreekt het voor mij van luiheid om foutcontrole in je scripts te negeren ... dus houd dat in gedachten, ook met deze werkgever ... als ze het veel gebruiken, hoe zien hun scripts eruit, dat jij zal onvermijdelijk moeten handhaven ... - cpbills
uitstekend punt @cpbills. Ik zie ook geen gebruik van set -e in een script en het is waarschijnlijk waarom het me zo stumped. Ik wil graag alle vragen plaatsen, want sommige zijn echt goed en sommige zijn echt maf en willekeurig zoals deze. - egorgry
Ik heb het in veel cron-banen van het systeem gezien ... - Andrew


set -e beëindigt het script als een niet-nul-exitcode wordt aangetroffen, behalve onder bepaalde voorwaarden. Om de gevaren van het gebruik in enkele woorden samen te vatten: het gedraagt ​​zich niet hoe mensen denken dat het werkt.

Naar mijn mening moet het worden beschouwd als een gevaarlijke hack die alleen voor compatibiliteitsdoeleinden blijft bestaan. De set -e statement verandert shell niet van een taal die foutcodes gebruikt in een taal die op een uitzondering lijkende controlestroom gebruikt, het probeert slechts slecht dat gedrag te emuleren.

Greg Wooledge heeft veel te zeggen over de gevaren van set -e:

In de tweede link zijn er verschillende voorbeelden van het niet intuïtieve en onvoorspelbare gedrag van set -e.

Enkele voorbeelden van het niet intuïtieve gedrag van set -e (sommige zijn overgenomen van de wiki-link hierboven):

  • set -e
    x = 0
    laat x ++
    echo "x is $ x"
    Het bovenstaande zorgt ervoor dat het shellscript voortijdig wordt afgesloten, omdat let x++ geeft 0 terug, dat wordt behandeld door de let sleutelwoord als valse waarde en omgezet in een niet-nul-exitcode. set -e dit opmerkt en het script stilletjes beëindigt.
  • set -e
    [-d / opt / foo] && echo "Waarschuwing: foo is al geïnstalleerd. Zal overschrijven." > & 2
    echo "Installeren van foo ..."
    

    Het bovenstaande werkt zoals verwacht en drukt een waarschuwing af als /opt/foo bestaat al.

    set -e
    check_previous_install () {
        [-d / opt / foo] && echo "Waarschuwing: foo is al geïnstalleerd. Zal overschrijven." > & 2
    }
    
    check_previous_install
    echo "Installeren van foo ..."
    

    Het bovenstaande, ondanks het enige verschil dat een enkele regel is gerefactored in een functie, zal eindigen als /opt/foo bestaat niet. Dit komt omdat het feit dat het oorspronkelijk werkte een speciale uitzondering is op set -ezijn gedrag. Wanneer a && b retourneert niet-nul, wordt genegeerd door set -e. Echter, nu het een functie is, is de exit-code van de functie gelijk aan de exit-code van die opdracht en de functie die niet-nul retourneert zal het script in stilte beëindigen.

  • set -e
    IFS = $ '\ n' read -d '' -r -a config_vars <config
    

    Het bovenstaande zal de array lezen config_vars uit het bestand config. Zoals de auteur misschien van plan is, wordt het beëindigd met een foutmelding als config ontbreekt. Zoals de auteur misschien niet van plan is, wordt het stil als config eindigt niet in een nieuwe regel. Als set -e werden toen niet gebruikt config_vars zou alle regels van het bestand bevatten, ongeacht of deze in een nieuwe regel is geëindigd.

    Gebruikers van Sublime Text (en andere tekstverwerkers die nieuwe regels verkeerd afhandelen), let op.

  • set -e
    
    should_audit_user () {
        lokale groep groepen = "$ (groepen" $ 1 ")"
        voor groep in $ groepen; do
            als ["$ group" = audit]; retourneer vervolgens 0; fi
        gedaan
        terug 1
    }
    
    if should_audit_user "$ user"; dan
        logger 'Blah'
    fi
    

    De auteur hier kan redelijkerwijs verwachten dat als om welke reden dan ook de gebruiker $user bestaat niet, dan is de groups opdracht zal mislukken en het script zal eindigen in plaats van de gebruiker een taak ongecontroleerd laten uitvoeren. In dit geval echter de set -e beëindiging heeft nooit effect. Als $user kan om een ​​of andere reden niet worden gevonden, in plaats van het script te beëindigen, de should_audit_user functie retourneert alleen onjuiste gegevens als ware het set -e was niet van kracht.

    Dit is van toepassing op elke functie die wordt aangeroepen vanuit het conditiedeel van een if verklaring, maakt niet uit hoe diep genesteld, ongeacht waar deze is gedefinieerd, maakt niet uit, zelfs als je loopt set -e erin weer. Gebruik makend van if op elk moment volledig uitschakelt het effect van set -e totdat het conditieblok volledig is uitgevoerd. Als de auteur zich niet bewust is van deze valkuil, of zijn hele oproepstapel niet kent in alle mogelijke situaties waarin een functie kan worden aangeroepen, dan zullen ze buggycode en het valse gevoel van veiligheid schrijven dat door set -e zal op zijn minst gedeeltelijk de schuld krijgen.

    Zelfs als de auteur volledig op de hoogte is van deze valkuil, is de oplossing om code op dezelfde manier te schrijven als je zou schrijven zonder set -e, waardoor die switch effectief minder dan nutteloos is; niet alleen moet de auteur een handmatige foutverwerkingscode schrijven alsof hij dat wil set -e waren niet van kracht, maar de aanwezigheid van set -e Misschien hebben ze hen voor de gek gehouden door te denken dat ze dat niet hoeven te doen.

Enkele verdere nadelen van set -e:

  • Het moedigt slordige code aan. Foutbehandelaars zijn volledig vergeten, in de hoop dat wat fout is gegaan de fout op een of andere verstandige manier zal melden. Echter, met voorbeelden zoals let x++ hierboven is dit niet het geval. Als het script onverwachts overlijdt, is het meestal stil, wat foutopsporing hindert. Als het script niet sterft en je verwacht dat het (zie vorige opsommingsteken), dan heb je een meer subtiele en verraderlijke bug in je handen.
  • Het leidt mensen naar een vals gevoel van veiligheid. Zie opnieuw de if-voorwaarde opsommingsteken.
  • De plaatsen waar de shell eindigt, zijn niet consistent tussen shells of shell-versies. Het is mogelijk om per ongeluk een script te schrijven dat zich anders gedraagt ​​op een oudere versie van bash vanwege het gedrag van set -e tussen die versies geknepen zijn.

set -e is een omstreden kwestie, en sommige mensen die zich bewust zijn van de problemen eromheen bevelen het af, terwijl sommige anderen alleen maar aanraden voorzichtig te zijn terwijl het actief is om de valkuilen te kennen. Er zijn veel shell scripting newbies die aanbevelen set -eop alle scripts als een alles overziende foutcondities, maar in het echt werkt het niet op die manier.

set -e is geen vervanging voor het onderwijs.


5
2018-04-27 23:06





Ik zou zeggen dat het gevaarlijk is, omdat je de stroom van je script niet meer onder controle hebt. Het script kan worden beëindigd zolang een van de opdrachten die door het script worden aangeroepen, een niet-nul retourneert. Dus alles wat je hoeft te doen is om iets te doen dat het gedrag of de uitvoer van een van de componenten verandert, en je mag het hoofdscript beëindigen. Het is misschien meer een stijlprobleem, maar het heeft zeker consequenties. Wat als dat hoofdscript van je verondersteld werd een vlag te zetten, en dat gebeurde niet omdat het vroegtijdig werd beëindigd? Uiteindelijk zou je de rest van het systeem tekort doen als het veronderstelt dat de vlag er zou moeten zijn, of zou je moeten werken met een onverwachte standaard of oude waarde.


2
2018-05-19 18:07



Helemaal mee eens met dit antwoord. Het is niet inherent gevaarlijk, maar het is een kans om een ​​onverwachte vroege exit te hebben. - pboin
Wat dit deed me denken aan is een C + + prof van mij die altijd punten uit mijn opdrachten trok voor het niet hebben van een enkel toegangspunt / single exitpunt in een programma. Ik dacht dat het een puur een 'principe'-ding was, maar deze set -e business demonstreert zeker hoe en waarom dingen volledig uit de hand kunnen lopen. Uiteindelijk gaan programma's over controle en determinisme, en met voortijdige beëindiging geef je beide op. - Marcin


Als een meer concreet voorbeeld van het antwoord van @ Marcin dat mij persoonlijk heeft gebeten, stel je voor dat er een was rm foo/bar.txt regel ergens in je script. Meestal geen probleem als foo/bar.txt bestaat niet echt. Echter met set -e presenteer nu je script zal daar vroeg eindigen! Oeps.


0
2018-06-22 19:00