Astuce : ajouter des options dans un script Bash avec getopt

But : com­prendre le fonc­tion­ne­ment de getopt en Bash pour évi­ter la mul­ti­pli­ca­tions de script là où un seul géné­rique pour­rait suf­fire.

Pré­re­quis : savoir faire des scripts Bash, connaître la sub­sti­tu­tion de com­mande et savoir mani­pu­ler les argu­ments.

Dif­fi­cul­té : 2 (moyen)

Pour ceux qui codent en Perl, vous connais­sez déjà sûre­ment le module GetOpt et plus par­ti­cu­liè­re­ment son exten­sion GetOpt::Long (ou encore le module getopt du lan­gage Python). Mais pour ceux qui sou­haitent juste faire un script qui enchaine les grep et les cut pour pou­voir comp­ter le nombre d'occurence d'une clé en fonc­tion de cer­tains cri­tères, il peut être utile de pou­voir le faire uni­que­ment en Bash plu­tôt que de se lan­cer dans un script Perl de plus. Dans cet article, je me pro­pose donc de vous pré­sen­ter la com­mande getopt illus­trée d'un exemple simple.

Script bash en cours d'édition sous VIM
Script bash en cours d'édition sous VIM (auteur : Nol­wenn) | Licence Art Libre

Voi­ci à quoi res­semble la pre­mière étape :

Ligne 1 :

  • getopt est le nom de la com­mande
  • -o pour les options courtes, c'est à dire une lettre par option
    • h sera une option courte, pour affi­cher l'aide par exemple
  • -l pour les options longues, c'est à dire un ensemble de lettres, comme un mot
    • home sera une option longue simple
    • nb_​fichiers : sera une option longue atten­dant un argu­ment en para­mètre
  • - — pour le com­por­te­ment par défaut

Pour ana­ly­ser les options, on uti­lise une boucle :

Ana­ly­sons cette por­tion de code :

  • while true ; do [..] done : une simple boucle while qui sera exé­cu­tée jusqu'à ce que le script soit ter­mi­né ;
  • case $1 in [..] esac : on regarde le pre­mier argu­ment et on com­pare son résul­tat à l'un des cas atten­dus par le script ;
  • -h : si $1 vaut ‑h, alors on exé­cute la fonc­tion usage() et on ter­mine le script ;
  • - ‑home : si $1 vaut — ‑home, alors on exé­cute la fonc­tion show­Home() et on sup­prime l'argument $1 ;
  • - ‑nb_​fichiers : si $1 vaut — ‑nb_​fichiers, alors on affiche la ligne avec le nom du réper­toire don­né dans $2 et on sup­prime les argu­ments $1 et $2 ;
  • - — : si $1 vaut — - on sup­prime l'argument $1 et on effec­tue un break (com­por­te­ment de fin atten­du par case [..] esac)

Le script final, de mon cru et sous licence GPL ;), pour­ra ain­si res­sem­bler à ceci :

Vous voi­là parés pour faire de jolis scripts Shell/​Bash com­plexes avec des argu­ments et des options dans tous les sens 😉 !


Un grand mer­ci à Haut­bit et Yoann M. pour leur relec­ture et nos dis­cus­sions.
Un remer­cie­ment tout par­ti­cu­lier à Syl­vain P. pour m'avoir fait décou­vrir cette mer­veilleuse com­mande Bash !



Pour continuer la lecture :


Commentaires

8 réponses à “Astuce : ajouter des options dans un script Bash avec getopt”

  1. Salut,

    Une remarque sur le code bash, pas sur getopt qui est bien pré­sen­té (même si par nature, ça fait très for­mule magique comme fonc­tion).

    $ mkdir "reper­toire avec espaces"
    $ bash ./test_getopts.sh –nb reper­toire\ avec\ espaces/​
    Ce n'est pas un réper­toire !

    Quand on n'a pas la maî­trise de ce qui entre comme dans le cas d'une action d'un uti­li­sa­teur (!), il faut être très pru­dent et blin­der le code.

    Les variables sont à pro­té­ger avec "$1" ou même "${1}".

    Bonne conti­nua­tion.
    KooK

    1. Avatar de Nolwenn

      Mer­ci pour l'astuce, il est vrai que je n'y ai pas pen­sé du tout, étant don­né que j'ai pris l'habitude de ne jamais mettre d'espace dans un nom de répertoire/​fichier. Ce qui n'est mal­heu­reu­se­ment pas tou­jours le cas de tout le monde, nous avons cha­cun nos petite manies. En plus, j'ai appris une nou­velle astuce de pro­gram­ma­tion 😉 !

  2. Avatar de Phinestra
    Phinestra

    bon­jour,

    j'aimerai savoir com­ment faire si je veux à la fois ren­trer 3 options. par exemple pour une connexion à un switch j'ai besoin de 3 options longues.

    mer­ci pour toute aide.
    phi.

    1. Avatar de Nolwenn

      Bon­jour,

      il vous suf­fit de sai­sir dans le switch autant d'options que néces­saires puis de gérer le trai­te­ment des options ren­sei­gnées.
      Vous n'aurez alors qu'à sai­sir vos trois options longues les unes à la suite des autres comme dans n'importe quel pro­gramme. getopt est vrai­ment simple à uti­li­ser une fois que l'on a com­pris le fonc­tion­ne­ment de base 🙂 !

      Cor­dia­le­ment,
      Nol­wenn

  3. En essayant d'intégrer des options pro­pre­ment dans un script, j'ai lu que fina­le­ment getopt n'est pas for­cé­ment une bonne recom­man­da­tion parce que non stan­dard et implé­men­té de façons dif­fé­rentes.

    Ici : http://​mywi​ki​.woo​ledge​.org/​B​a​s​h​F​A​Q​/​035
    on trouve dif­fé­rentes pro­po­si­tions pour ana­ly­ser les options.

    Il me semble que du coup le code de cet article fonc­tion­ne­rait tout aus­si bien sans getopt, avec juste la boucle.

    1. Bon­jour KooK,

      mer­ci beau­coup pour cette remon­tée d'informations. Je vous avoue que je suis sur­prise étant don­né que j'avais lu l'inverse l'année der­nière, quelques semaines avant de rédi­ger cet article. Les normes auraient-elles chan­gé aus­si vite ?
      Si vous avez l'occasion de tes­ter la boucle sans getopt(s), je serais ravie d'en connaître le ver­dict 🙂 !

      Cor­dia­le­ment, Nol­wenn

  4. Si mes sou­ve­nirs sont bons, j'avais géré mes argu­ments dans un script Bash avec une boucle iden­tique, mais sans getop.
    Donc je pense que ça marche.

  5. Mer­ci pour ce tuto :). C'est exac­te­ment ce dont j'avais besoin : un tuto avec un exemple simple pour com­prendre rapi­de­ment com­ment faire un script bash avec des options. C'est quand même plus agréable que de se perdre dans les limbes d'internet sur des modes d'emploi abs­cons de 42 pages…
    En revanche, pour que ce script fonc­tionne chez moi (Mac OSX 10.6.8), j'ai dû :
    — com­men­ter « eval set — "$OPTS"»
    — rem­pla­cer le « true » de la boucle « while » par un boo­léen valant « true » si «$# != 0 » et « false » si aucun argu­ment «$# == 0 », car sinon, après l'appel de « usage », l'exécution ren­trait dans la boucle « while » qui ité­rait à l'infini (et c'est long l'infini, sur­tout vers la fin!)

Laisser un commentaire