Je ne sais pas comment inclure des arguments / indicateurs facultatifs lors de l'écriture d'un script bash pour le programme suivant:
Le programme nécessite deux arguments:
run_program --flag1 <value> --flag2 <value>
Cependant, il existe plusieurs indicateurs facultatifs:
run_program --flag1 <value> --flag2 <value> --optflag1 <value> --optflag2 <value> --optflag3 <value> --optflag4 <value> --optflag5 <value>
Je voudrais exécuter le script bash de telle sorte qu'il prenne des arguments utilisateur. Si les utilisateurs ne saisissent que deux arguments dans l'ordre, ce serait:
#!/bin/sh
run_program --flag1 $1 --flag2 $2
Mais que se passe-t-il si l'un des arguments facultatifs est inclus? Je pense que ce serait
if [ --optflag1 "$3" ]; then
run_program --flag1 $1 --flag2 $2 --optflag1 $3
fi
Mais que se passe-t-il si 4 $ sont donnés mais pas 3 $?
shell-script
arguments
ShanZhengYang
la source
la source
getopts
c'est ce que tu veux. Sans cela, vous pourriez utiliser une boucle avec une instruction switch pour détecter chaque indicateur, facultatif ou non.getopts
, aurais-je besoin de spécifier chaque combinaison d'arguments? 3 & 4, 3 & 5, 3 & 4 & 5, etc.?getopts
. Disons que je force les utilisateurs à exécuter le script avec tous les arguments:run_program.sh VAL VAL FALSE FALSE FALSE FALSE FALSE
qui exécute le programme en tant queprogram --flag1 VAL --flag2 VAL
. Si vous exécutiezrun_program.sh VAL VAL FALSE 10 FALSE FALSE FALSE
, le programme s'exécuterait sousprogram --flag1 VAL --flag2 VAL --optflag2 10
. Comment pouvez-vous obtenir un tel comportementgetopts
?Réponses:
Cet article présente deux manières différentes -
shift
etgetopts
(et présente les avantages et les inconvénients des deux approches).Avec
shift
votre apparence de script à$1
, décide des mesures à prendre, puis exécuteshift
, en mouvement$2
à$1
,$3
à$2
, etc.Par exemple:
Avec
getopts
vous définissez les options (courtes) dans l'while
expression:Évidemment, ce ne sont que des extraits de code, et j'ai laissé de côté la validation - en vérifiant que les arguments obligatoires flag1 et flag2 sont définis, etc.
Quelle approche vous utilisez est dans une certaine mesure une question de goût - comment portable vous voulez que votre script soit, si vous pouvez vivre avec des options courtes (POSIX) seulement ou si vous voulez des options longues (GNU), etc.
la source
while (( $# ))
au lieu dewhile :;
et quitte souvent avec une erreur dans le*
casset -o nounset
la première solution, l'erreur se produira si aucun paramètre n'est donné. Corrigé:case ${1:-} in
utilisez un tableau.
cela gérera correctement les arguments avec des espaces.
[modifier] J'utilisais la syntaxe à peu près équivalente
args=( "${args[@]}" --optflag1 "$3" )
mais G-Man a suggéré une meilleure façon.la source
args+=( --optflag1 "$3" )
. Vous voudrez peut-être voir ma réponse à notre travail de référence, Conséquences pour la sécurité de ne pas citer une variable dans les shells bash / POSIX , où je discute de cette technique (de construction d'une ligne de commande dans un tableau en ajoutant conditionnellement des arguments facultatifs).[@]
que j'avais un outil suffisant pour résoudre mon problème.Dans un script shell, les arguments sont "$ 1", "$ 2", "$ 3", etc. Le nombre d'arguments est $ #.
Si votre script ne reconnaît pas les options, vous pouvez exclure la détection des options et traiter tous les arguments comme des opérandes.
Pour reconnaître les options, utilisez le getopts intégré
la source
Si vos options de saisie sont positionnelles (vous savez à quels endroits elles se trouvent), et non spécifiées avec des drapeaux, alors ce que vous voulez est simplement de construire la ligne de commande. Préparez simplement les arguments de commande pour chacun d'eux:
Si les paramètres ne sont pas spécifiés, les chaînes correspondantes sont vides et se développent en rien. Notez que dans la dernière ligne, il n'y a pas de guillemets. C'est parce que vous voulez que le shell divise les paramètres en mots (pour donner
--flag1
et$1
comme arguments séparés à votre programme). Bien sûr, cela ira mal si vos paramètres d'origine contiennent des espaces. Si vous êtes celui qui exécute cela, vous pouvez le laisser, mais s'il s'agit d'un script général, il peut avoir un comportement inattendu si l'utilisateur entre quelque chose avec des espaces. Pour gérer cela, vous devrez rendre le code un peu plus laid.Le
x
préfixe du[]
test est là au cas où$3
ou$4
est vide. Dans ce cas, bash se développerait[ FALSE != $3 ]
dans[ FALSE != ]
ce qui est une erreur de syntaxe, donc un autre caractère arbitraire est là pour se prémunir contre cela. C'est un moyen très courant, vous le verrez dans de nombreux scripts.Je les ai définis
OPTFLAG1
et les autres""
au début juste pour être sûr (au cas où ils auraient été définis sur quelque chose auparavant), mais s'ils n'étaient pas réellement déclarés dans l'environnement, alors vous n'avez pas strictement besoin de le faire.Quelques remarques supplémentaires:
runprogram
: avec des drapeaux. Voilà de quoiJohn N
parle. C'est là quegetopts
devient utile.-
) pour signaler une valeur vide, ou simplement passer une chaîne vide, comme""
, si ce n'est pas autrement une valeur valide du paramètre. Une chaîne vide raccourcit également le test, il suffit de l'utiliserif [ -n "$3" ]
.""
des paramètres vides, comme suggéré ci-dessus, vous pouvez de toute façon ignorer tous les vides de fin.Cette méthode est à peu près la façon dont les options sont passées aux compilateurs dans Makefiles.
Et encore une fois - si les entrées peuvent contenir des espaces, cela devient moche.
la source