392 votes

Comment obtenir des arguments avec des drapeaux en Bash

Je sais que je peux facilement obtenir des paramètres positionnés comme ceci dans bash :

$0 ou $1

Je veux pouvoir utiliser des options de drapeau comme celle-ci pour préciser à quoi sert chaque paramètre :

mysql -u user -h host

Quel est le meilleur moyen d'obtenir -u param valeur et -h param par drapeau plutôt que par position ?

2 votes

Ce serait une bonne idée de demander/vérifier à unix.stackexchange.com également

13 votes

Cherchez sur Google "bash getopts" -- beaucoup de tutoriels.

139 votes

@glenn-jackman : Je vais certainement le googler maintenant que je connais le nom. Le truc avec Google, c'est que pour poser une question, il faut déjà connaître 50% de la réponse.

672voto

Dennis Points 5020

Cet exemple utilise la fonction intégrée de Bash getopts et provient de la commande Guide de style Google Shell :

a_flag=''
b_flag=''
files=''
verbose='false'

print_usage() {
  printf "Usage: ..."
}

while getopts 'abf:v' flag; do
  case "${flag}" in
    a) a_flag='true' ;;
    b) b_flag='true' ;;
    f) files="${OPTARG}" ;;
    v) verbose='true' ;;
    *) print_usage
       exit 1 ;;
  esac
done

Note : Si un caractère est suivi d'un deux-points (ex. f: ), cette option est censée avoir un argument.

Exemple d'utilisation : ./script -v -a -b -f filename

L'utilisation de getopts présente plusieurs avantages par rapport à la réponse acceptée :

  • la condition while est beaucoup plus lisible et montre quelles sont les options acceptées
  • code plus propre ; pas de comptage du nombre de paramètres et de décalage
  • vous pouvez joindre des options (par exemple -a -b -c -abc )

Cependant, il présente un inconvénient majeur : il ne prend pas en charge les options longues, mais uniquement les options à un seul caractère.

67 votes

On peut se demander pourquoi cette réponse, qui consiste à utiliser un buildin bash, n'est pas la meilleure.

47 votes

Pour la postérité : les deux points après 'abf:v' indiquent que -f prend un argument supplémentaire (le nom du fichier dans ce cas).

1 votes

J'ai dû changer la ligne d'erreur en ceci : ?) printf '\nUsage: %s: [-a] aflag [-b] bflag\n' $0; exit 2 ;;

391voto

Flexo Points 39273

C'est l'idiome que j'utilise habituellement :

while test $# -gt 0; do
  case "$1" in
    -h|--help)
      echo "$package - attempt to capture frames"
      echo " "
      echo "$package [options] application [arguments]"
      echo " "
      echo "options:"
      echo "-h, --help                show brief help"
      echo "-a, --action=ACTION       specify an action to use"
      echo "-o, --output-dir=DIR      specify a directory to store output in"
      exit 0
      ;;
    -a)
      shift
      if test $# -gt 0; then
        export PROCESS=$1
      else
        echo "no process specified"
        exit 1
      fi
      shift
      ;;
    --action*)
      export PROCESS=`echo $1 | sed -e 's/^[^=]*=//g'`
      shift
      ;;
    -o)
      shift
      if test $# -gt 0; then
        export OUTPUT=$1
      else
        echo "no output dir specified"
        exit 1
      fi
      shift
      ;;
    --output-dir*)
      export OUTPUT=`echo $1 | sed -e 's/^[^=]*=//g'`
      shift
      ;;
    *)
      break
      ;;
  esac
done

Les points clés sont les suivants :

  • $# est le nombre d'arguments
  • La boucle while examine tous les arguments fournis, en faisant correspondre leurs valeurs à l'intérieur d'une instruction case.
  • L'équipe prend le premier. Vous pouvez utiliser shift plusieurs fois dans une instruction case pour prendre plusieurs valeurs.

4 votes

Que fait le --action* y --output-dir* les cas font ?

1 votes

Ils ne font que sauvegarder les valeurs qu'ils obtiennent dans l'environnement.

28 votes

@Lucio Super vieux commentaire, mais je l'ajoute au cas où quelqu'un d'autre visiterait un jour cette page. Le * (joker) est pour le cas où quelqu'un tape --action=[ACTION] ainsi que le cas où quelqu'un tape --action [ACTION]

52voto

Shizzmo Points 4695

Getopt est votre ami un exemple simple :

function f () {
TEMP=`getopt --long -o "u:h:" "$@"`
eval set -- "$TEMP"
while true ; do
    case "$1" in
        -u )
            user=$2
            shift 2
        ;;
        -h )
            host=$2
            shift 2
        ;;
        *)
            break
        ;;
    esac 
done;

echo "user = $user, host = $host"
}

f -u myself -h some_host

Il devrait y avoir plusieurs exemples dans votre répertoire /usr/bin.

4 votes

Un exemple plus complet se trouve dans le répertoire /usr/share/doc/util-linux/examples au moins sur les machines Ubuntu.

0 votes

@Shizzmo Pouvez-vous expliquer la syntaxe de set -- ? J'ai vu cet idiome à plusieurs reprises. Je vous en serais reconnaissant. Merci beaucoup.

0 votes

32voto

pijemcolu Points 847

Je propose un exemple simple TLDR: ; pour les non-initiés.

Créer un script bash appelé greeter.sh

#!/bin/bash

while getopts "n:" arg; do
  case $arg in
    n) Name=$OPTARG;;
  esac
done

echo "Hello $Name!"

Vous pouvez ensuite passer un paramètre facultatif -n lors de l'exécution du script.

Exécutez le script comme tel :

$ bash greeter.sh -n 'Bob'

Sortie

$ Hello Bob!

Notes

Si vous souhaitez utiliser plusieurs paramètres :

  1. étendre while getops "n:" arg: do avec plus de paramètres tels que while getops "n:o:p:" arg: do
  2. étendre le commutateur de cas avec des affectations de variables supplémentaires. Par exemple o) Option=$OPTARG y p) Parameter=$OPTARG

Pour rendre le script exécutable :

chmod u+x greeter.sh

18voto

Matias Barrios Points 1654

Je pense que cela pourrait servir d'exemple plus simple de ce que vous voulez réaliser. Il n'est pas nécessaire d'utiliser des outils externes. Les outils intégrés à Bash peuvent faire le travail pour vous.

function DOSOMETHING {

   while test $# -gt 0; do
           case "$1" in
                -first)
                    shift
                    first_argument=$1
                    shift
                    ;;
                -last)
                    shift
                    last_argument=$1
                    shift
                    ;;
                *)
                   echo "$1 is not a recognized flag!"
                   return 1;
                   ;;
          esac
  done  

  echo "First argument : $first_argument";
  echo "Last argument : $last_argument";
 }

Cela vous permettra d'utiliser des drapeaux afin que, quel que soit l'ordre dans lequel vous passez les paramètres, vous obteniez le comportement approprié.

Exemple :

 DOSOMETHING -last "Adios" -first "Hola"

Sortie :

 First argument : Hola
 Last argument : Adios

Vous pouvez ajouter cette fonction à votre profil ou la placer à l'intérieur d'un script.

Merci !

Edit : Enregistrez ce fichier et exécutez-le sous la forme suivante yourfile.sh -last "Adios" -first "Hola"

#!/bin/bash
while test $# -gt 0; do
           case "$1" in
                -first)
                    shift
                    first_argument=$1
                    shift
                    ;;
                -last)
                    shift
                    last_argument=$1
                    shift
                    ;;
                *)
                   echo "$1 is not a recognized flag!"
                   return 1;
                   ;;
          esac
  done  

  echo "First argument : $first_argument";
  echo "Last argument : $last_argument";

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X