Comment utiliser getopt dans la command line bash avec seulement des options longues?

Il y a une command getopt dans la command line bash. getopt peut être utilisé avec des options courtes (comme getopt -o axby "$@" ), et peut être utilisé avec des options courtes et longues (comme getopt -o axby -l long-key -- "$@" ), mais maintenant je n'ai besoin que de longues options (c.-à-d. les options courtes n'existent pas du tout), cependant la command getopt -l long-key -- "$@" --long-key pas correctement l'option --long-key . Alors, comment puis-je utiliser la command getopt avec seulement des options longues? Ou est-il impossible ou est-ce juste un bug de la command getopt ?

getopt est parfaitement bien avec aucune option courte. Mais vous devez lui dire que vous n'avez pas d'options courtes. C'est une bizarrerie dans la syntaxe – du manuel:

Si aucune option -o ou --options n'est trouvée dans la première partie, le premier paramètre de la deuxième partie est utilisé comme string d'options courtes.

C'est ce qui se passe dans votre test: getopt -l long-key -- --long-key foo --long-key getopt -l long-key -- --long-key foo --long-key comme la list des options -egklnoy et foo comme seul argument. Utilisation

 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' 

Dunno à propos de getopt mais le getopts builtin peut être utilisé pour gérer seulement les longues options comme ceci:

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

Bien sûr, en l'état, cela ne fonctionne pas si les options longues sont censées avoir des arguments. Cela peut être fait, cependant, mais, comme j'ai appris à travailler là-dessus. Bien que je l'ai initialement inclus ici, j'ai réalisé que pour les options longues, il n'a pas beaucoup d'utilité. Dans ce cas, il ne faisait que raccourcir mes champs de case (match) par un seul caractère prévisible. Maintenant, ce que je sais, c'est qu'il est excellent pour les options courtes – il est très utile quand il boucle sur une string de longueur inconnue et en sélectionnant des octets uniques en fonction de sa string d'options. Mais quand l'option est l'arg, il n'y a pas beaucoup de choses que vous faites avec un for var do case $var in combinaison que cela pourrait faire. C'est mieux, je pense, de restr simple.

Je soupçonne la même chose de getopt mais je n'en sais pas assez pour dire avec certitude. Étant donné le tableau arg suivant, je vais démontrer mon propre petit parsingur arg – qui dépend principalement de la relation d'évaluation / d'affectation que j'ai appréciée 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 

C'est la string d'arg avec laquelle je vais travailler. À présent:

 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 atsortingbuez un ou deux sets d'arguments séparés par le -- délimiteur. Dans les deux cas, il s'applique aux séquences de traitement du tableau arg.

Si vous l'appelez comme:

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

Son premier ordre d'affaires sera d'é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é du shift 3 . La substitution de command dans la définition de la fonction acase() est évaluée lorsque le shell appelant construit l'input de la fonction ici-documents, mais acase() n'est jamais appelée ou définie dans le shell appelant. Bien entendu, il est appelé dans le sous-shell, de sorte que vous pouvez spécifier dynamicment les options d'intérêt sur la command line.

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

La fonction effectue pratiquement tout son traitement dans le sous-shell – sauvegardant de manière itérative chacune des valeurs de l'arg aux alias assignés avec des noms associatifs. Quand il est à travers, il imprime toutes les valeurs qu'il a sauvegardées avec alias – qui est POSIX – spécifié pour imprimer toutes les valeurs enregistrées de telle manière que leurs valeurs peuvent être réinjectées dans le shell. Alors quand je le fais …

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

Sa sortie 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' 

Au fur et à mesure qu'il parcourt la list d'arguments, il vérifie le bloc de cas pour une correspondance. S'il trouve une correspondance, il lève un drapeau – f=optname . Jusqu'à ce qu'il trouve à nouveau une option valide, il appenda chaque argument suivant à un tableau qu'il construit en fonction du drapeau courant. Si la même option est spécifiée plusieurs fois, les résultats sont composés et ne remplacent pas. Tout ce qui n'est pas dans le cas – ou tout argument suivant les options ignorées – est assigné à un tableau ignoré .

La sortie est shell-safed pour l'input shell automatiquement par le shell, et ainsi:

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

… devrait être parfaitement sûr. Si pour une raison quelconque, il n'est pas sûr, vous devriez probablement déposer un rapport de bogue avec votre mainteneur de shell.

Il affecte deux types de valeurs d'alias pour chaque correspondance. Tout d'abord, il définit un drapeau – cela se produit si une option précède ou non les arguments non correspondants. Ainsi, toute occurrence de --flag dans la list d'arguments triggersra flag=1 . Cela ne --flag --flag --flag pas – --flag --flag --flag obtient juste flag=1 . Cette valeur incrémente cependant – pour tous les arguments qui pourraient le suivre. Il peut être utilisé comme une key d'index. Après avoir fait l' eval ci-dessus, je peux faire:

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

…get…

 8 1 

Et donc:

 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 pour les arguments qui ne correspondaient pas je substituerais ignoré dans ce qui précède for ... in champ pour get:

 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