Question Que fait 'set-e', et pourquoi pourrait-il être considéré comme dangereux?


Cette question est apparue dans un quiz de pré-entretien et ça me rend fou. Quelqu'un peut-il répondre à cela et me mettre à l'aise? Le quiz ne fait pas référence à un shell en particulier, mais la description du poste concerne un système d'exploitation unix. encore une fois la question est simplement ...

Que fait 'set-e', et pourquoi pourrait-il être considéré comme dangereux?


141
2018-05-19 16:39


origine


Voici un fil connexe: stackoverflow.com/questions/64786/error-handling-in-bash/… - Stefan Lasiewski


Réponses:


set -e provoque la fermeture du shell si une sous-commande ou un pipeline renvoie un statut différent de zéro.

La réponse que l'intervieweur recherchait probablement est la suivante:

Il serait dangereux d'utiliser "set -e" lors de la création de scripts init.d:

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

Faites attention à l'utilisation de set -e dans les scripts init.d. L'écriture de scripts init.d correct nécessite l'acceptation de divers statuts de sortie d'erreur lorsque les démons sont déjà en cours d'exécution ou déjà arrêtés sans abandonner le script init.d, et que les bibliothèques de fonctions init.d courantes ne peuvent pas être appelées avec set -e en vigueur. Pour les scripts init.d, il est souvent plus facile de ne pas utiliser set -e et de vérifier le résultat de chaque commande séparément.

C'est une question valable du point de vue de l'interviewer, car elle évalue la connaissance pratique du candidat en script et en automatisation au niveau du serveur.


146
2017-08-09 21:01



belle trouvaille. Merci. - egorgry
bon point. cela arrêterait le processus de démarrage sur quelque chose qui pourrait techniquement être une erreur, mais ne devrait pas causer l'arrêt complet du script - Matt
Bien que je suis d'accord avec stackoverflow.com/questions/78497/…, Je pense que ce style s’accorde bien avec bash pour les vérifications d’initialisation initiales et la journalisation ou les autres correctifs d’environnement avant d’exécuter le workload cible. Nous utilisons cette même politique pour nos scripts d'initialisation d'image docker. - joshperry


De 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.

Malheureusement, je ne suis pas assez créatif pour imaginer pourquoi cela serait dangereux, si ce n’est "le reste du script ne sera pas exécuté" ou "cela masquera peut-être de vrais problèmes".


33
2018-05-19 16:43



masque de vrais problèmes / autres problèmes, oui, je suppose que je pouvais voir que ... je me débattais pour trouver un exemple dangereux, aussi ... - cpbills
Il y a la page de manuel pour set! Je finis toujours à builtin(1). Merci. - Jared Beck
comment saurais-je que la documentation de set doit être trouvé dans man 1 bash?? et comment quiconque pourrait-il trouver le -e option pour le set mot clé dans une page de manuel qui est tellement énorme? tu ne peux pas juste /-e cherche ici - Blauhirn
@Blauhirn utilisant help set - Blauhirn


Il convient de noter que set -e peut être activé et désactivé pour différentes sections d'un script. Il n'est pas nécessaire qu'il soit activé pour l'exécution du script entier. Il pourrait même être activé de manière conditionnelle. Cela dit, je ne l'utilise jamais puisque je gère (ou non) ma propre erreur.

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

Il convient également de noter ceci dans la section de la page de manuel Bash du trap commande qui décrit également comment set -e fonctionne dans certaines circonstances.

le                 ERR trap n'est pas exécuté si la commande en échec fait partie de la                 liste de commandes suivant immédiatement un mot-clé while ou Until,                 partie du test dans une instruction if, partie d'une commande exécutée                 dans une liste && ou, ou si la valeur de retour de la commande est en cours                 via inversé! Ce sont les mêmes conditions obéies par le                 Option errexit.

Il existe donc certaines conditions dans lesquelles un statut différent de zéro ne provoquera pas de sortie.

Je pense que le danger est de ne pas comprendre quand set -e entre en jeu et quand il ne le fait pas et en s’appuyant de façon incorrecte sur une hypothèse invalide.

S'il vous plaît voir aussi BashFAQ / 105 Pourquoi set -e (ou set -o errexit, ou piège ERR) ne répond-il pas à mes attentes?


19
2018-05-19 22:39



Bien que déviant un peu de la question, cette réponse est exactement ce que je recherche: la désactiver pour seulement une petite partie d'un script! - Stephan Bijzitter


Gardez à l'esprit qu'il s'agit d'un questionnaire pour un entretien d'embauche. Les questions ont peut-être été écrites par le personnel actuel et peuvent être fausses. Ce n’est pas nécessairement mauvais, et tout le monde fait des erreurs, et les questions posées lors des entretiens restent souvent sans réponse dans un coin sombre, et ne se posent qu’au cours d’une interview.

Il est tout à fait possible que "set -e" ne fasse rien que nous considérions comme "dangereux". Mais l'auteur de cette question peut croire à tort que "set-e" est dangereux, en raison de leur ignorance ou de leurs préjugés. Peut-être qu'ils ont écrit un script shell buggy, le bombardement a été horrible, et ils ont pensé à tort que «set-e» était à blâmer, alors qu'en fait ils ont négligé d'écrire la vérification d'erreur correcte.

J'ai participé à probablement 40 entretiens d'embauche au cours des deux dernières années, et les intervieweurs posent parfois des questions incorrectes ou des réponses erronées.

Ou peut-être que c'est une question piège, qui serait boiteuse, mais pas totalement inattendue.

Ou peut-être est-ce une bonne explication: http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg473314.html


13
2018-05-19 17:03



+1 Je suis dans le même bateau, et bon nombre des entretiens «techniques» auxquels j'ai eu à faire ont été au moins légèrement erronés. - cpbills
sensationnel. Bonne trouvaille sur la liste debian. +1 pour l'ignorance des questions d'entrevue. Je me souviens d'avoir disputé une réponse au netback une fois, car j'étais à 100% sûr d'avoir raison. Ils ont dit non. Je suis rentré chez moi et l'ai googlé, j'avais raison. - egorgry


set -e indique à bash, dans un script, de quitter chaque fois que quelque chose retourne une valeur de retour non nulle.

Je pouvais voir à quel point cela pouvait être ennuyeux, et buggué, pas sûr de dangereux, à moins que vous n'ayez ouvert des autorisations sur quelque chose, et avant de pouvoir les restreindre à nouveau, votre script est mort.


9
2018-05-19 16:46



C'est intéressant. Je ne pensais pas aux autorisations ouvertes dans un script qui meurt prématurément, mais je pouvais voir que cela était considéré comme dangereux. La partie amusante de ce quiz est que vous ne pouvez utiliser aucun document de référence tel que man ou google. Si vous ne pouvez pas répondre complètement, n'y répondez pas du tout. - egorgry
C'est juste idiot, je reconsidérerais cet employeur ... je plaisante (en quelque sorte). Il est bon d'avoir une base de connaissances solide, mais la moitié du travail informatique consiste à savoir / où / trouver l'information ... J'espère qu'ils ont été assez intelligents pour en tenir compte lors de la notation des candidats. sur une note de côté, je vois / non / utiliser pour set -eEn fait, pour moi, cela parle de paresse d’ignorer les erreurs de vérification dans vos scripts ... alors gardez cela à l’esprit, avec cet employeur aussi ... s’ils l’utilisent beaucoup, à quoi ressemblent leurs scripts, que vous devra inévitablement maintenir ... - cpbills
excellent point @ cpbills. Je ne vois également aucune utilité pour set -e dans un script et c'est probablement pourquoi il m'a tellement bouleversé. Je voudrais poster toutes les questions car certaines sont vraiment bonnes et certaines sont vraiment farfelues et aléatoires comme celle-ci. - egorgry
Je l'ai vu dans de nombreux jobs système cron ... - Andrew


set -e termine le script si un code de sortie différent de zéro est rencontré, sauf dans certaines conditions. Pour résumer les dangers de son utilisation en quelques mots: il ne se comporte pas comme les gens le pensent.

À mon avis, il devrait être considéré comme un piratage dangereux qui continue d'exister uniquement à des fins de compatibilité. le set -e instruction ne transforme pas le shell d’un langage qui utilise des codes d’erreur en un langage qui utilise un flux de contrôle semblable à une exception, il tente simplement de simuler ce comportement.

Greg Wooledge a beaucoup à dire sur les dangers de set -e:

Dans le deuxième lien, il existe divers exemples de comportement non intuitif et imprévisible de set -e.

Quelques exemples de comportement non intuitif de set -e (certains tirés du lien wiki ci-dessus):

  • set -e
    x = 0
    laisser x ++
    echo "x est $ x"
    Ce qui précède entraînera la fermeture prématurée du script shell, car let x++ renvoie 0, qui est traité par le let mot-clé en tant que valeur falsy et transformé en un code de sortie différent de zéro. set -e le remarque et termine silencieusement le script.
  • set -e
    [-d / opt / foo] && echo "Attention: foo est déjà installé. Écrasera." > & 2
    echo "Installation de foo ..."
    

    Ce qui précède fonctionne comme prévu et affiche un avertissement si /opt/foo existe déjà.

    set -e
    check_previous_install () {
        [-d / opt / foo] && echo "Attention: foo est déjà installé. Écrasera." > & 2
    }
    
    check_previous_install
    echo "Installation de foo ..."
    

    Ce qui précède, bien que la seule différence est qu’une seule ligne a été refactorisée en une fonction, s’arrêtera si /opt/foo n'existe pas. En effet, le fait qu’il ait fonctionné à l’origine constitue une exception spéciale à set -ele comportement de. Quand a && b renvoie non nul, il est ignoré par set -e. Cependant, maintenant que c'est une fonction, le code de sortie de la fonction est égal au code de sortie de cette commande, et la fonction renvoyant une valeur autre que zéro mettra fin au script de manière silencieuse.

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

    Ce qui précède lira le tableau config_vars du fichier config. Comme l’intéressé le souhaite, il se termine par une erreur si config est manquant. Comme l’auteur n’a peut-être pas l’intention de le faire, il se termine en silence config ne se termine pas par une nouvelle ligne. Si set -e n'ont pas été utilisés ici, alors config_vars contiendrait toutes les lignes du fichier, qu'il se termine ou non par une nouvelle ligne.

    Utilisateurs de Sublime Text (et des autres éditeurs de texte gérant mal les nouvelles lignes), méfiez-vous.

  • set -e
    
    should_audit_user () {
        groupes de groupes locaux = "$ (groupes" $ 1 ")"
        pour groupe en $ groupes; faire
            if ["$ group" = audit]; puis retourne 0; Fi
        terminé
        retour 1
    }
    
    if should_audit_user "$ user"; puis
        bûcheron 'Blah'
    Fi
    

    L’auteur peut raisonnablement s’attendre à ce que si, pour une raison quelconque, l’utilisateur $user n'existe pas, alors le groups La commande échouera et le script se terminera au lieu de laisser l'utilisateur effectuer une tâche non vérifiée. Cependant, dans ce cas, le set -e la résiliation ne prend jamais effet. Si $user ne peut pas être trouvé pour une raison quelconque, au lieu de terminer le script, le should_audit_user la fonction va simplement renvoyer des données incorrectes comme si set -e n'était pas en vigueur.

    Ceci s’applique à toute fonction appelée à partir de la partie condition d’un objet. if déclaration, peu importe la profondeur de l'imbrication, peu importe où elle est définie, peu importe si vous exécutez set -e à l'intérieur de nouveau. En utilisant if à tout moment désactive complètement l'effet de set -e jusqu'à ce que le bloc de condition soit complètement exécuté. Si l'auteur n'est pas conscient de ce piège ou ne connaît pas l'intégralité de sa pile d'appels dans toutes les situations possibles dans lesquelles une fonction peut être appelée, il écrira un code erroné et le faux sentiment de sécurité fourni par set -e sera au moins partiellement à blâmer.

    Même si l'auteur est pleinement conscient de ce piège, la solution consiste à écrire du code de la même manière que l'on l'écrirait sans set -e, rendant effectivement ce changement moins inutile. non seulement l'auteur doit écrire le code de traitement d'erreur manuel comme si set -e n'étaient pas en vigueur, mais la présence de set -e peut les avoir dupés en pensant qu'ils ne doivent pas.

Quelques autres inconvénients de set -e:

  • Cela encourage le code bâclé. Les gestionnaires d’erreur sont complètement oubliés, dans l’espoir que tout ce qui échouera signalera l’erreur d’une manière raisonnable. Cependant, avec des exemples comme let x++ ci-dessus, ce n'est pas le cas. Si le script meurt de manière inattendue, il s’agit généralement de manière silencieuse, ce qui empêche le débogage. Si le script ne meurt pas et que vous vous attendiez à le voir (voir le point précédent), alors vous avez un bug plus subtil et insidieux sur vos mains.
  • Cela amène les gens à un faux sentiment de sécurité. Revoir le if-condition balle point.
  • Les endroits où se termine le shell ne sont pas cohérents entre les shell ou les versions de shell. Il est possible d’écrire accidentellement un script qui se comporte différemment sur une ancienne version de bash en raison du comportement de set -e avoir été modifié entre ces versions.

set -e est une question controversée, et certaines personnes au courant des problèmes qui l’entourent la recommandent, alors que d’autres recommandent simplement de faire attention pendant qu’il est actif de connaître les pièges. Il y a beaucoup de débutants en scripts shell qui recommandent set -esur tous les scripts en tant que fourre-tout pour les conditions d'erreur, mais dans la vraie vie, cela ne fonctionne pas de cette façon.

set -e n'est pas un substitut à l'éducation.


5
2018-04-27 23:06





Je dirais que c'est dangereux parce que vous ne contrôlez plus le déroulement de votre script. Le script peut se terminer tant que l'une des commandes qu'il invoque renvoie une valeur autre que zéro. Donc, tout ce que vous avez à faire est de faire quelque chose qui modifie le comportement ou la sortie de l'un des composants, et vous devez terminer le script principal. Ce pourrait être plus un problème de style, mais cela a certainement des conséquences. Que se passe-t-il si votre script principal est supposé définir un drapeau, mais il ne l’a pas fait car il s’est terminé tôt? Si vous supposez que l'indicateur doit être présent, ou si vous utilisez une valeur par défaut ou une ancienne valeur inattendue, vous finirez par mettre en défaut le reste du système.


2
2018-05-19 18:07



Totalement d'accord avec cette réponse. Ce n'est pas intrinsèquement dangereux, mais c’est une occasion d’avoir une sortie anticipée inattendue. - pboin
Cela m’a rappelé un de mes profs C ++ qui tirait toujours des points de mes affectations pour ne pas avoir un point d’entrée / un point de sortie unique dans un programme. Je pensais que c'était purement un «principe», mais cette entreprise a définitivement démontré comment et pourquoi les choses peuvent complètement échapper à tout contrôle. En fin de compte, les programmes sont axés sur le contrôle et le déterminisme et, avec une cessation prématurée, vous abandonnez les deux. - Marcin