Je sais que je peux facilement obtenir des paramètres positionnés comme celui-ci dans bash:
$0
ou $1
Je veux pouvoir utiliser des options de drapeau comme celle-ci pour spécifier les paramètres utilisés:
mysql -u user -h Host
Quel est le meilleur moyen d’obtenir la valeur -u param
et la valeur -h param
par indicateur au lieu de par position?
C'est le langage 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:
$#
est le nombre d'argumentsCet exemple utilise la commande intégrée getopts
de Bash et provient du Guide de style de 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
Remarque: si un caractère est suivi de deux points (par exemple, f:
), cette option devrait 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:
-a -b -c
→ -abc
)Cependant, un gros inconvénient est qu’il ne prend pas en charge les options longues, mais uniquement les options à un seul caractère.
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 divers exemples dans votre répertoire/usr/bin.
Je pense que cela servirait 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 de 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 indicateurs afin que vous obteniez le comportement approprié, quel que soit l'ordre dans lequel vous transmettez les paramètres.
Exemple :
DOSOMETHING -last "Adios" -first "Hola"
Sortie:
First argument : Hola
Last argument : Adios
Vous pouvez ajouter cette fonction à votre profil ou la placer dans un script.
Merci!
Edit: enregistrez ceci en tant que fichier puis exécutez-le en tant que 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";
Une autre alternative serait d’utiliser quelque chose comme l’exemple ci-dessous qui vous permettrait d’utiliser des balises longues - image ou courtes - i et d’autoriser les balises compilées - i = "example.jpg" ou séparez - i example.jpg méthodes de transmission 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";
J'aime bien la réponse de Robert McMahan, car il semble plus facile de transformer des fichiers d'inclusion partageables que vos scripts peuvent utiliser. Mais il semble y avoir un défaut avec la ligne if [[ -n ${variables[$argument_label]} ]]
en lançant le message, "variables: bad array subscript". Je n'ai pas le représentant à commenter, et je doute que ce soit la "solution" appropriée, mais envelopper cette if
dans if [[ -n $argument_label ]] ; then
le nettoie.
Voici le code avec lequel je me suis retrouvé. Si vous connaissez un meilleur moyen, veuillez ajouter un commentaire à la réponse de Robert.
Fichier d'inclusion "flags-declares.sh"
# declaring a couple of associative arrays
declare -A arguments=();
declare -A variables=();
# declaring an index integer
declare -i index=1;
Fichier d'inclusion "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";
Si vous connaissez Python argparse et que vous appelez python pour analyser les arguments bash, voici un morceau de code que j'ai trouvé vraiment utile et très facile à utiliser appelé argparse -bash https://github.com/nhoffman/argparse-bash
Exemple tiré de leur script example.sh:
#!/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
Je propose un TLDR simple :; exemple pour les non initiés.
Créez un script bash appelé helloworld.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écute le script en tant que tel:
$ bash helloworld.sh -n 'World'
sortie
$ Hello World!
Notes
Si vous souhaitez utiliser plusieurs paramètres:
while getops "n:" arg: do
avec plus de paramètres tels que while getops "n:o:p:" arg: do
o) Option=$OPTARG
et p) Parameter=$OPTARG