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.

10voto

Robert McMahan Points 341

Une autre alternative serait d'utiliser quelque chose comme l'exemple ci-dessous qui vous permettrait d'utiliser de longs --image ou court -i et permettent également aux balises compilées -i="exemple.jpg" ou séparés -i exemple.jpg des méthodes pour passer des arguments.

# declaring a couple of associative arrays
declare -A arguments=();  
declare -A variables=();

# declaring an index integer
declare -i index=1;

# any variables you want to use here
# on the left left side is argument label or key (entered at the command line along with it's value) 
# on the right side is the variable name the value of these arguments should be mapped to.
# (the examples above show how these are being passed into this script)
variables["-gu"]="git_user";  
variables["--git-user"]="git_user";  
variables["-gb"]="git_branch";  
variables["--git-branch"]="git_branch";  
variables["-dbr"]="db_fqdn";  
variables["--db-redirect"]="db_fqdn";  
variables["-e"]="environment";  
variables["--environment"]="environment";

# $@ here represents all arguments passed in
for i in "$@"  
do  
  arguments[$index]=$i;
  prev_index="$(expr $index - 1)";

  # this if block does something akin to "where $i contains ="
  # "%=*" here strips out everything from the = to the end of the argument leaving only the label
  if [[ $i == *"="* ]]
    then argument_label=${i%=*} 
    else argument_label=${arguments[$prev_index]}
  fi

  # this if block only evaluates to true if the argument label exists in the variables array
  if [[ -n ${variables[$argument_label]} ]]
    then
        # dynamically creating variables names using declare
        # "#$argument_label=" here strips out the label leaving only the value
        if [[ $i == *"="* ]]
            then declare ${variables[$argument_label]}=${i#$argument_label=} 
            else declare ${variables[$argument_label]}=${arguments[$index]}
        fi
  fi

  index=index+1;
done;

# then you could simply use the variables like so:
echo "$git_user";

6voto

Michael Points 31

J'aime la réponse de Robert McMahan car elle semble la plus facile à faire dans des fichiers include partageables pour n'importe lequel de vos scripts à utiliser. Mais elle semble avoir un défaut avec la ligne if [[ -n ${variables[$argument_label]} ]] le message suivant apparaît : "variables : bad array subscript". Je n'ai pas la réputation pour commenter, et je doute que ce soit le bon "correctif", mais en enveloppant cela if en if [[ -n $argument_label ]] ; then le nettoie.

Voici le code que j'ai obtenu. Si vous connaissez une meilleure méthode, veuillez ajouter un commentaire à la réponse de Robert.

Inclure le fichier "flags-declares.sh".

# declaring a couple of associative arrays
declare -A arguments=();
declare -A variables=();

# declaring an index integer
declare -i index=1;

Inclure le fichier "flags-arguments.sh".

# $@ here represents all arguments passed in
for i in "$@"
do
  arguments[$index]=$i;
  prev_index="$(expr $index - 1)";

  # this if block does something akin to "where $i contains ="
  # "%=*" here strips out everything from the = to the end of the argument leaving only the label
  if [[ $i == *"="* ]]
    then argument_label=${i%=*}
    else argument_label=${arguments[$prev_index]}
  fi

  if [[ -n $argument_label ]] ; then
    # this if block only evaluates to true if the argument label exists in the variables array
    if [[ -n ${variables[$argument_label]} ]] ; then
      # dynamically creating variables names using declare
      # "#$argument_label=" here strips out the label leaving only the value
      if [[ $i == *"="* ]]
        then declare ${variables[$argument_label]}=${i#$argument_label=} 
        else declare ${variables[$argument_label]}=${arguments[$index]}
      fi
    fi
  fi

  index=index+1;
done;

Votre "script.sh"

. bin/includes/flags-declares.sh

# any variables you want to use here
# on the left left side is argument label or key (entered at the command line along with it's value) 
# on the right side is the variable name the value of these arguments should be mapped to.
# (the examples above show how these are being passed into this script)
variables["-gu"]="git_user";
variables["--git-user"]="git_user";
variables["-gb"]="git_branch";
variables["--git-branch"]="git_branch";
variables["-dbr"]="db_fqdn";
variables["--db-redirect"]="db_fqdn";
variables["-e"]="environment";
variables["--environment"]="environment";

. bin/includes/flags-arguments.sh

# then you could simply use the variables like so:
echo "$git_user";
echo "$git_branch";
echo "$db_fqdn";
echo "$environment";

4voto

Nishant Ingle Points 405
#!/bin/bash

if getopts "n:" arg; then
  echo "Welcome $OPTARG"
fi

Enregistrez-le sous le nom de sample.sh et essayez d'exécuter

sh sample.sh -n John

dans votre terminal.

3voto

Linh Points 169

Si vous êtes familier avec Python argparse, et que cela ne vous dérange pas d'appeler python pour analyser les arguments de bash, il y a un morceau de code que j'ai trouvé très utile et très facile à utiliser appelé argparse-bash. https://github.com/nhoffman/argparse-bash

Exemple tiré de leur exemple.sh script :

#!/bin/bash

source $(dirname $0)/argparse.bash || exit 1
argparse "$@" <<EOF || exit 1
parser.add_argument('infile')
parser.add_argument('outfile')
parser.add_argument('-a', '--the-answer', default=42, type=int,
                    help='Pick a number [default %(default)s]')
parser.add_argument('-d', '--do-the-thing', action='store_true',
                    default=False, help='store a boolean [default %(default)s]')
parser.add_argument('-m', '--multiple', nargs='+',
                    help='multiple values allowed')
EOF

echo required infile: "$INFILE"
echo required outfile: "$OUTFILE"
echo the answer: "$THE_ANSWER"
echo -n do the thing?
if [[ $DO_THE_THING ]]; then
    echo " yes, do it"
else
    echo " no, do not do it"
fi
echo -n "arg with multiple values: "
for a in "${MULTIPLE[@]}"; do
    echo -n "[$a] "
done
echo

3voto

J'avais des difficultés à utiliser getopts avec plusieurs drapeaux, alors j'ai écrit ce code. Il utilise une variable modale pour détecter les drapeaux, et pour utiliser ces drapeaux pour assigner des arguments aux variables.

Notez que, si un drapeau ne doit pas avoir d'argument, quelque chose d'autre que de définir CURRENTFLAG peut être fait.

    for MYFIELD in "$@"; do

        CHECKFIRST=`echo $MYFIELD | cut -c1`

        if [ "$CHECKFIRST" == "-" ]; then
            mode="flag"
        else
            mode="arg"
        fi

        if [ "$mode" == "flag" ]; then
            case $MYFIELD in
                -a)
                    CURRENTFLAG="VARIABLE_A"
                    ;;
                -b)
                    CURRENTFLAG="VARIABLE_B"
                    ;;
                -c)
                    CURRENTFLAG="VARIABLE_C"
                    ;;
            esac
        elif [ "$mode" == "arg" ]; then
            case $CURRENTFLAG in
                VARIABLE_A)
                    VARIABLE_A="$MYFIELD"
                    ;;
                VARIABLE_B)
                    VARIABLE_B="$MYFIELD"
                    ;;
                VARIABLE_C)
                    VARIABLE_C="$MYFIELD"
                    ;;
            esac
        fi
    done

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