Comment utiliser getopt en ligne de commande bash avec uniquement des options longues?

Il y a une commande getopt dans la ligne de commande bash. getopt peut être utilisé avec des options courtes (telles que getopt -o axby "$@"), et peut être utilisé avec des options courtes et longues (telles que getopt -o axby -l long-key -- "$@"), mais maintenant jai besoin seulement doptions longues (cest-à-dire que les options courtes nexistent pas du tout), mais la commande getopt -l long-key -- "$@" nanalyse pas correctement loption --long-key. Alors, comment puis-je utiliser la commande getopt avec uniquement options longues? Ou est-ce impossible ou est-ce juste un bug de la commande getopt?

Commentaires

  • Vous balise pour la getopts, mais vous utilisez la commande /usr/bin/getopt.
  • @Anthon Désolé, jai utilisé la mauvaise balise, mais je nai ' pas assez de réputations pour ajouter une autre balise, qui a besoin de 300 réputations. Cependant, je viens de supprimer la mauvaise balise.

Réponse

getopt convient parfaitement de ne pas avoir doptions courtes. Mais vous devez lui dire que vous navez pas doptions courtes. Cest une bizarrerie dans la syntaxe – du manuel:

Si non -o ou --options se trouve dans la première partie, le premier paramètre de la deuxième partie est utilisé comme chaîne doptions courte.

Cest ce qui se passe dans votre test: getopt -l long-key -- --long-key foo traite --long-key comme la liste doptions -egklnoy et foo comme seul argument. Utilisez

getopt -o "" -l long-key -- "$@" 

par exemple

$ getopt -l long-key -o "" -- --long-key foo --long-key -- "foo" $ getopt -l long-key -o "" -- --long-key --not-recognized -n foo getopt: unrecognized option "--not-recognized" getopt: invalid option -- "n" --long-key -- "foo" 

Commentaires

  • Le PO ' a-t-il mélangé getopts et getopt infectent votre réponse? Vous commencez par commenter getopts puis ne mentionnez que getopt.
  • @Anthon Toute ma réponse concerne le programme getopt de GNU coreutils qui est le sujet de la question. I a corrigé le texte qui disait getopts. Merci. getopts ne ' même pas faire des options longues, donc rien de tout cela ne sappliquerait à getopts .
  • LOP avait à lorigine la balise getopts. Je ne voulais pas changer votre réponse, car vous savez normalement beaucoup mieux que moi ce que vous écrivez 🙂
  • Jai perdu presque une heure à essayer de comprendre. Vous venez de me sauver quelques vaines gorgées de café. Merci … mettons ce café à un meilleur usage maintenant. ☕️

Réponse

Je ne sais pas à propos de getopt mais le getopts builtin peut être utilisé pour gérer uniquement des options longues comme celle-ci:

while getopts :-: o do case "$o$OPTARG" in (-longopt1) process ;; (-longopt2) process ;; esac; done 

Bien sûr, tel quel, cela ne fonctionne pas  » t fonctionner si les options longues sont supposées avoir des arguments. Cela peut être fait, cependant, mais, comme je l « ai appris à travailler là-dessus. Alors que je lai initialement inclus ici, jai réalisé que pour les options longues, il navait pas beaucoup dutilité. Dans ce cas, il ne faisait que raccourcir mon case (match) par un seul caractère prévisible. Maintenant, ce que je sais, cest quil est excellent pour les options courtes – il est plus utile quand il boucle sur une chaîne de longueur inconnue et sélectionne un octet en fonction de sa chaîne doptions . Mais lorsque l’option est l’argument, vous ne faites pas grand chose avec une combinaison for var do case $var in que cela pourrait faire. Il vaut mieux, Je pense, pour faire simple.

Je soupçonne que la même chose est vraie pour getopt mais je nen sais pas assez pour le dire avec certitude. Étant donné le tableau arg suivant, je vais démontrer mon propre petit analyseur darguments – qui dépend principalement de la relation évaluation / affectation que jai appris à apprécier pour alias et $((shell=math)).

set -- this is ignored by default --lopt1 -s "some "\"" args" here --ignored and these are ignored \ --alsoignored andthis --lopt2 "and some "`more" --lopt1 and just a few more 

Cest la chaîne arg avec laquelle je » vais travailler. Maintenant:

aopts() { env - sh -s -- "$@" } <<OPTCASE 3<<\OPTSCRIPT acase() case "\$a" in $(fmt=" (%s) f=%s; aset "?$(($f)):";;\n" for a do case "$a" in (--) break;; (--*[!_[:alnum:]]*) continue;; (--*) printf "$fmt" "$a" "${a#--}";; esac;done;printf "$fmt" "--*" ignored) (*) aset "" "\$a";;esac shift "$((SHIFT$$))"; f=ignored; exec <&3 OPTCASE aset() { alias "$f=$(($f${1:-=$(($f))+}1))" [ -n "${2+?}" ] && alias "${f}_$(($f))=$2"; } for a do acase; done; alias #END OPTSCRIPT 

Cela traite le tableau arg de deux manières différentes selon que vous lui donnez un ou deux ensembles darguments séparés par le délimiteur --. Dans les deux cas, cela sapplique aux séquences de traitement du tableau arg.

Si vous lappelez comme:

: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@" 

Son premier ordre de lentreprise devra écrire sa fonction acase() pour ressembler à:

acase() case "$a" in (--lopt1) f=lopt1; aset "?$(($f)):";; (--lopt2) f=lopt2; aset "?$(($f)):";; (--*) f=ignored; aset "?$(($f)):";; (*) aset "" "$a";;esac 

Et à côté de shift 3.La substitution de commande dans la définition de la fonction acase() est évaluée lorsque le shell appelant construit les documents dentrée ici de la fonction, mais acase() est jamais appelé ou défini dans le shell appelant. Il est appelé dans le sous-shell, bien sûr, et ainsi vous pouvez spécifier dynamiquement les options qui vous intéressent sur la ligne de commande.

Si vous lui donnez un tableau non délimité, il remplit simplement acase() avec des correspondances pour tous les arguments commençant par la chaîne --.

La fonction effectue pratiquement tout son traitement dans le sous-shell – en sauvegardant de manière itérative chacune des valeurs de arg dans des alias attribués avec des noms associatifs. Lorsquil est terminé, il imprime toutes les valeurs enregistrées avec alias – qui est spécifié par POSIX pour imprimer toutes les valeurs enregistrées citées de manière à ce que leurs valeurs puissent être réintroduites dans le shell. Alors quand je le fais …

aopts --lopt1 --lopt2 -- "$@" 

Son résultat ressemble à ceci:

...ignored... lopt1="8" lopt1_1="-s" lopt1_2="some "\"" args" lopt1_3="here" lopt1_4="and" lopt1_5="just" lopt1_6="a" lopt1_7="few" lopt1_8="more" lopt2="1" lopt2_1="and some "`more" 

En parcourant la liste darguments, il vérifie par rapport au bloc de cas une correspondance. Sil y trouve une correspondance, il lance un drapeau – f=optname. Jusquà ce quil trouve à nouveau une option valide, il ajoutera chaque argument suivant à un tableau quil construit en fonction de lindicateur actuel. Si la même option est spécifiée plusieurs fois, les résultats sont composés et ne sont pas remplacés. Tout ce qui nest pas au cas où – ou tout argument suivant des options ignorées – est assigné à un tableau ignoré .

La sortie est sécurisée par le shell pour lentrée du shell automatiquement par le shell, et ainsi :

eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")" 

… devrait être parfaitement sûr. Si pour une raison quelconque nest pas sûr, alors vous devriez probablement déposer un rapport de bogue auprès de votre responsable du shell.

Il attribue deux types de valeurs dalias pour chaque correspondance. Tout dabord, il définit un indicateur – cela se produit, quune option précède ou non les arguments non correspondants. Ainsi, toute occurrence de --flag dans la liste darguments déclenchera flag=1. Cela ne compose pas – --flag --flag --flag obtient juste flag=1. Cette valeur sincrémente cependant – pour tous les arguments qui pourraient la suivre. Il peut être utilisé comme clé dindex. Après avoir fait le eval ci-dessus, je peux faire:

printf %s\\n "$lopt1" "$lopt2" 

… pour obtenir …

8 1 

Et ainsi:

for o in lopt1 lopt2 do list= i=0; echo "$o = $(($o))" while [ "$((i=$i+1))" -le "$(($o))" ] do list="$list $o $i \"\${${o}_$i}\" " done; eval "printf "%s[%02d] = %s\n" $list"; done 

SORTIE

lopt1 = 8 lopt1[01] = -s lopt1[02] = some " args lopt1[03] = here lopt1[04] = and lopt1[05] = just lopt1[06] = a lopt1[07] = few lopt1[08] = more lopt2 = 1 lopt2[01] = and some "`more 

Et aux arguments qui ne correspondent pas, je remplacerais ignored dans le champ for ... in ci-dessus pour obtenir:

ignored = 10 ignored[01] = this ignored[02] = is ignored[03] = ignored ignored[04] = by ignored[05] = default ignored[06] = and ignored[07] = these ignored[08] = are ignored[09] = ignored ignored[10] = andthis 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *