Comment utiliser getops pour analyser les options de script du shell Linux

Publié: 2022-06-25
Un écran d'ordinateur portable affichant le texte du terminal.
fatmawati achmad zaenuri/Shutterstock.com

Souhaitez-vous que vos scripts shell Linux gèrent plus gracieusement les options et les arguments de la ligne de commande ? La fonction intégrée getopts de Bash vous permet d'analyser les options de ligne de commande avec finesse, et c'est aussi facile. Nous vous montrons comment.

Présentation de la fonction intégrée getopts

Passer des valeurs dans un script Bash est assez simple. Vous appelez votre script à partir de la ligne de commande ou d'un autre script et fournissez votre liste de valeurs derrière le nom du script. Ces valeurs sont accessibles dans votre script en tant que variables, en commençant par $1 pour la première variable, $2 pour la seconde et ainsi de suite.

Mais si vous souhaitez passer des options à un script, la situation devient vite plus complexe. Lorsque nous parlons d'options, nous entendons les options, les drapeaux ou les commutateurs que des programmes comme ls peuvent gérer. Ils sont précédés d'un tiret « - » et servent généralement d'indicateur au programme pour activer ou désactiver certains aspects de ses fonctionnalités.

Comment utiliser la commande ls pour répertorier les fichiers et les répertoires sous Linux
CONNEXION Comment utiliser la commande ls pour répertorier les fichiers et les répertoires sous Linux

La commande ls a plus de 50 options, principalement liées au formatage de sa sortie. L'option -X (trier par extension) trie la sortie alphabétiquement par extension de fichier. L'option -U (non triée) répertorie par ordre de répertoire.

Les options ne sont que cela : elles sont facultatives. Vous ne savez pas quelles options, le cas échéant, l'utilisateur va choisir d'utiliser, et vous ne savez pas non plus dans quel ordre il peut les lister sur la ligne de commande. Cela augmente la complexité du code requis pour analyser les options.

Les choses deviennent encore plus compliquées si certaines de vos options prennent un argument, connu sous le nom d' option argument , Par exemple, l'option ls -w (width) s'attend à être suivie d'un nombre, représentant la largeur d'affichage maximale de la sortie. Et bien sûr, vous pourriez passer d'autres paramètres dans votre script qui sont simplement des valeurs de données, qui ne sont pas du tout des options.

Heureusement getopts gère cette complexité pour vous. Et parce que c'est un intégré, il est disponible sur tous les systèmes qui ont le shell Bash, donc il n'y a rien à installer.

Remarque : getops Pas getopt

Il existe un ancien utilitaire appelé getopt . Il s'agit d'un petit programme utilitaire, pas d'un fichier intégré. Il existe de nombreuses versions différentes de getopt avec des comportements différents, tandis que la getops suit les directives POSIX.

 tapez getops
 tapez getopt 

en utilisant la commande type pour voir la différence entre getop et getops

Étant donné que getopt n'est pas intégré, il ne partage pas certains des avantages automatiques de getopts , tels que la gestion raisonnable des espaces blancs. Avec getopts , le shell Bash exécute votre script et le shell Bash effectue l'analyse des options. Vous n'avez pas besoin d'invoquer un programme externe pour gérer l'analyse.

Le compromis est que getopts ne gère pas les noms d'options au format long en double tiret. Vous pouvez donc utiliser des options formatées comme -w mais pas " ---wide-format ". D'un autre côté, si vous avez un script qui accepte les options -a , -b et -c , getopts vous permet de les combiner comme -abc , -bca ou -bac et ainsi de suite.

Nous discutons et démontrons getopts dans cet article, alors assurez-vous d'ajouter le « s » final au nom de la commande.

CONNEXION: Comment échapper aux espaces dans les chemins de fichiers sur la ligne de commande Windows

Un récapitulatif rapide : gestion des valeurs de paramètre

Ce script n'utilise pas d'options en pointillés comme -a ou -b . Il accepte les paramètres "normaux" sur la ligne de commande et ceux-ci sont accessibles à l'intérieur du script en tant que valeurs.

 #!/bin/bash

# récupère les variables une par une
echo "Variable 1 : $1" 
echo "Variable deux : $2" 
echo "Variable trois : $3"

# boucle dans les variables
pour var dans " $@" faire
echo "$ var" 
Fini

Les paramètres sont accessibles à l'intérieur du script en tant que variables $1 , $2 ou $3 .

Copiez ce texte dans un éditeur et enregistrez-le dans un fichier appelé "variables.sh". Nous devrons le rendre exécutable avec la commande chmod . Vous devrez effectuer cette étape pour tous les scripts dont nous discutons. Remplacez simplement le nom du fichier de script approprié à chaque fois.

 chmod +x variables.sh 

utiliser la commande chmod pour rendre un script exécutable

Si nous exécutons notre script sans paramètres, nous obtenons cette sortie.

 ./variables.sh 

exécuter un script sans paramètres

Nous n'avons passé aucun paramètre, le script n'a donc aucune valeur à signaler. Donnons quelques paramètres cette fois.

 ./variables.sh comment geek 

exécuter un script avec trois mots comme paramètres

Comme prévu, les variables $1 , $2 et $3 ont été définies sur les valeurs des paramètres et nous les voyons imprimées.

Ce type de gestion des paramètres un pour un signifie que nous devons savoir à l'avance combien de paramètres il y aura. La boucle au bas du script ne se soucie pas du nombre de paramètres, elle les parcourt toujours tous.

Si nous fournissons un quatrième paramètre, il n'est pas affecté à une variable, mais la boucle le gère toujours.

 ./variables.sh comment créer un site Web geek 

passer quatre paramètres à un script qui ne peut en gérer que trois

Si nous mettons des guillemets autour de deux des mots, ils sont traités comme un seul paramètre.

 ./variables.sh comment "geek" 

citer deux paramètres de ligne de commande pour les traiter comme un seul paramètre

Si nous voulons que notre script gère toutes les combinaisons d'options, d'options avec arguments et de paramètres de type de données "normaux", nous devrons séparer les options des paramètres normaux. Nous pouvons y parvenir en plaçant toutes les options, avec ou sans arguments, avant les paramètres normaux.

Mais ne courons pas avant de pouvoir marcher. Examinons le cas le plus simple pour gérer les options de ligne de commande.

Options de manipulation

Nous utilisons getopts dans une boucle while . Chaque itération de la boucle fonctionne sur une option qui a été transmise au script. Dans chaque cas, la variable OPTION est définie sur l'option identifiée par getopts .

A chaque itération de la boucle, getopts passe à l'option suivante. Lorsqu'il n'y a plus d'options, getopts renvoie false et la boucle while se termine.

Comment utiliser les instructions de cas dans les scripts Bash
CONNEXION Comment utiliser les instructions de cas dans les scripts Bash

La variable OPTION est mise en correspondance avec les modèles de chacune des clauses de l'instruction case. Comme nous utilisons une instruction case, peu importe l'ordre dans lequel les options sont fournies sur la ligne de commande. Chaque option est déposée dans l'instruction case et la clause appropriée est déclenchée.

Les clauses individuelles de l'instruction case facilitent l'exécution d'actions spécifiques à une option dans le script. En règle générale, dans un script réel, vous définiriez une variable dans chaque clause, et celles-ci agiraient comme des drapeaux plus loin dans le script, autorisant ou refusant certaines fonctionnalités.

Copiez ce texte dans un éditeur et enregistrez-le en tant que script appelé "options.sh", et rendez-le exécutable.

 #!/bin/bash

tandis que getopts 'abc' OPTION ; fais
  cas "$OPTION" dans 
    un) 
      echo "Option a utilisée" ;;

    b)
      echo "Option b utilisée"
      ;;

    c)
      echo "Option c utilisée"
      ;;

    ?) 
      echo "Utilisation : $(basename $0) [-a] [-b] [-c]"
      sortie 1
      ;;
  esac
Fini

C'est la ligne qui définit la boucle while.

 tandis que getopts 'abc' OPTION ; fais

La commande getopts est suivie de la chaîne d'options . Ceci répertorie les lettres que nous allons utiliser comme options. Seules les lettres de cette liste peuvent être utilisées comme options. Donc dans ce cas, -d serait invalide. Cela serait piégé par la clause ?) car getopts renvoie un point d'interrogation « ? ” pour une option non identifiée. Si cela se produit, l'utilisation correcte est imprimée dans la fenêtre du terminal :

 echo "Utilisation : $(basename $0) [-a] [-b] [-c]"

Par convention, envelopper une option entre crochets " [] " dans ce type de message d'utilisation correcte signifie que l'option est facultative. La commande basename supprime tous les chemins de répertoire du nom de fichier. Le nom du fichier de script est contenu dans $0 dans les scripts Bash.

Utilisons ce script avec différentes combinaisons de ligne de commande.

 ./options.sh -a
 ./options.sh -a -b -c
 ./options.sh -ab -c
 ./options.sh -cab 

tester un script qui peut accepter les options de ligne de commande de type commutateur

Comme nous pouvons le voir, toutes nos combinaisons d'options de test sont analysées et gérées correctement. Et si on essayait une option qui n'existe pas ?

 ./options.sh -d 

Une option non reconnue signalée par le shell et le script

La clause d'utilisation est déclenchée, ce qui est bien, mais nous recevons également un message d'erreur du shell. Cela peut ou non avoir de l'importance pour votre cas d'utilisation. Si vous appelez le script à partir d'un autre script qui doit analyser les messages d'erreur, cela compliquera la tâche si le shell génère également des messages d'erreur.

Désactiver les messages d'erreur du shell est très simple. Tout ce que nous avons à faire est de mettre deux-points ” : ” comme premier caractère de la chaîne d'options.

Modifiez votre fichier "options.sh" et ajoutez deux points comme premier caractère de la chaîne d'options, ou enregistrez ce script sous "options2.sh" et rendez-le exécutable.

 #!/bin/bash

tandis que getopts ':abc' OPTION ; fais
  cas "$OPTION" dans 
    un) 
      echo "Option a utilisée" 
      ;;

    b)
      echo "Option b utilisée"
      ;;

    c)
      echo "Option c utilisée"
      ;;

    ?) 
      echo "Utilisation : $(basename $0) [-a] [-b] [-c]"
      sortie 1
      ;;
  esac
Fini

Lorsque nous exécutons ceci et générons une erreur, nous recevons nos propres messages d'erreur sans aucun message shell.

 ./options2.sh.sh -d 

Une option non reconnue signalée par le script seul

Utilisation de getops avec des arguments d'option

Pour indiquer à getopts qu'une option sera suivie d'un argument, placez deux-points " : " immédiatement après la lettre d'option dans la chaîne d'options.

Si nous suivons le « b » et le « c » dans notre chaîne d'options avec deux-points, getopt attendra des arguments pour ces options. Copiez ce script dans votre éditeur et enregistrez-le sous "arguments.sh", et rendez-le exécutable.

N'oubliez pas que le premier deux-points de la chaîne d'options est utilisé pour supprimer les messages d'erreur du shell - cela n'a rien à voir avec le traitement des arguments.

Lorsque getopt traite une option avec un argument, l'argument est placé dans la variable OPTARG . Si vous souhaitez utiliser cette valeur ailleurs dans votre script, vous devrez la copier dans une autre variable.

 #!/bin/bash

tandis que getopts ':ab:c:' OPTION ; fais

  cas "$OPTION" dans
    un)
      echo "Option a utilisée"
      ;;

    b)
      argB="$OPTARG"
      echo "Option b utilisée avec : $argB"
      ;;

    c)
      argC="$OPTARG"
      echo "Option c utilisée avec : $argC"
      ;;

    ?)
      echo "Utilisation : $(basename $0) [-a] [-b argument] [-c argument]"
      sortie 1
      ;;
  esac

Fini

Exécutons cela et voyons comment cela fonctionne.

 ./arguments.sh -a -b "comment geek" -c reviewgeek
 ./arguments.sh -c reviewgeek -a 

tester un script capable de gérer les arguments d'option

Nous pouvons donc maintenant gérer les options avec ou sans arguments, quel que soit l'ordre dans lequel elles sont données sur la ligne de commande.

Mais qu'en est-il des paramètres réguliers ? Nous avons dit plus tôt que nous savions que nous devions les mettre sur la ligne de commande après toutes les options. Voyons ce qui se passe si nous le faisons.

Options et paramètres de mélange

Nous allons modifier notre script précédent pour inclure une ligne supplémentaire. Lorsque la boucle while est terminée et que toutes les options ont été gérées, nous essaierons d'accéder aux paramètres normaux. Nous imprimerons la valeur en $1 .

Enregistrez ce script sous "arguments2.sh" et rendez-le exécutable.

 #!/bin/bash

tandis que getopts ':ab:c:' OPTION ; fais

  cas "$OPTION" dans
    un)
      echo "Option a utilisée"
      ;;

    b)
      argB="$OPTARG"
      echo "Option b utilisée avec : $argB"
      ;;

    c)
      argC="$OPTARG"
      echo "Option c utilisée avec : $argC"
      ;;

    ?)
      echo "Utilisation : $(basename $0) [-a] [-b argument] [-c argument]"
      sortie 1
      ;;
  esac

Fini

echo "La variable 1 est : $1"

Nous allons maintenant essayer quelques combinaisons d'options et de paramètres.

 ./arguments2.sh dave
 ./arguments2.sh -a dave
 ./arguments2.sh -a -c how-to-geek dave 

Impossible d'accéder aux paramètres standard dans un script qui accepte les arguments d'option

Alors maintenant, nous pouvons voir le problème. Dès que des options sont utilisées, les variables à partir $1 sont remplies avec les drapeaux d'option et leurs arguments. Dans le dernier exemple, $4 contiendrait la valeur du paramètre "dave", mais comment y accéder dans votre script si vous ne savez pas combien d'options et d'arguments vont être utilisés ?

La réponse est d'utiliser OPTIND et la commande shift .

La commande shift supprime le premier paramètre, quel que soit son type, de la liste des paramètres. Les autres paramètres sont « décroissants », donc le paramètre 2 devient le paramètre 1, le paramètre 3 devient le paramètre 2, et ainsi de suite. Ainsi, $2 devient $1 $3 devient $2 , et ainsi de suite.

Si vous fournissez un shift avec un nombre, cela supprimera autant de paramètres de la liste.

OPTIND compte les options et les arguments au fur et à mesure qu'ils sont trouvés et traités. Une fois toutes les options et tous les arguments traités, OPTIND sera supérieur d'une unité au nombre d'options. Donc, si nous utilisons shift pour supprimer les paramètres (OPTIND-1) de la liste des paramètres, nous nous retrouverons avec les paramètres normaux à partir de $1 .

C'est exactement ce que fait ce script. Enregistrez ce script sous « arguments3.sh » et rendez-le exécutable.

 #!/bin/bash

tandis que getopts ':ab:c:' OPTION ; fais
  cas "$OPTION" dans
    un)
      echo "Option a utilisée"
      ;;

    b)
      argB="$OPTARG"
      echo "Option b utilisée avec : $argB"
      ;;

    c)
      argC="$OPTARG"
      echo "Option c utilisée avec : $argC"
      ;;

    ?)
      echo "Utilisation : $(basename $0) [-a] [-b argument] [-c argument]"
      sortie 1
      ;;
  esac
Fini

echo "Avant - la variable un est : $1"
décalage "$(($OPTIND -1))"
echo "Après - la variable un est : $1"
echo "Le reste des arguments (opérandes)"

pour x dans "$@"
fais
  écho $x
Fini

Nous allons l'exécuter avec un mélange d'options, d'arguments et de paramètres.

 ./arguments3.sh -a -c how-to-geek "dave dee" dozy beaky mick tich 

Accéder correctement aux paramètres standard dans un script qui accepte les arguments d'option

Nous pouvons voir qu'avant d'appeler shift , $1 contenait "-a", mais après la commande shift $1 contient notre premier paramètre sans option ni argument. Nous pouvons parcourir tous les paramètres aussi facilement que nous le pouvons dans un script sans analyse d'option.

C'est toujours bien d'avoir des options

La gestion des options et de leurs arguments dans les scripts n'a pas besoin d'être compliquée. Avec getopts , vous pouvez créer des scripts qui gèrent les options, les arguments et les paramètres de la ligne de commande exactement comme le devraient les scripts natifs compatibles POSIX.