Jak používat getopt v příkazovém řádku bash s pouze dlouhými možnostmi?

V příkazovém řádku bash je příkaz getopt. getopt lze použít s krátkými možnostmi (například getopt -o axby "$@") a lze ji použít s krátkými i dlouhými možnostmi (například getopt -o axby -l long-key -- "$@"), ale nyní potřebuji pouze dlouhé možnosti (tj. krátké možnosti vůbec neexistují), nicméně příkaz getopt -l long-key -- "$@" správně neaktualizuje možnost --long-key. Jak tedy mohu použít příkaz getopt s pouze dlouhými možnostmi? Nebo je to nemožné nebo je to jen chyba v příkazu getopt?

Komentáře

  • Vy značka pro interní getopts, ale používáte příkaz /usr/bin/getopt.
  • @Anthon Omlouvám se, použil jsem špatná značka, ale nemám ' dostatek reputací pro přidání další značky, která potřebuje 300 reputací. Právě jsem však odstranil nesprávnou značku.

Odpovědět

getopt je naprosto v pořádku, protože nemá žádné krátké možnosti. Musíte však říct, že nemáte žádné krátké možnosti. Je to vtípek v syntaxi – z příručky:

Pokud ne -o nebo --options možnost se nachází v první části, první parametr druhé části se použije jako řetězec krátkých voleb.

To se ve vašem testu děje: getopt -l long-key -- --long-key foo považuje --long-key za seznam možností -egklnoy a foo jako jediný argument. Použijte

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

např.

$ 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" 

Komentáře

  • Provedlo OP ' promíchání getopts a getopt infikovat vaši odpověď? Začnete komentováním getopts a poté pouze zmíníte getopt.
  • @Anthon Celá moje odpověď se týká programu getopt od GNU coreutils, což je otázka, o kterou jde. I opravili jsme text, který říká getopts. Dík. getopts nedělá ' ani dlouhé možnosti, takže nic z toho by se na getopts nevztahovalo .
  • OP měl původně značku getopts. Nechtěl jsem změnit vaši odpověď, protože obvykle víte mnohem lépe než já, o čem píšete 🙂
  • Ztratil jsem téměř hodinu tím, že jsem na to přišel. Právě jsi mi zachránil několik marných doušků kávy. Díky … pojďme teď tuto kávu lépe využít. ☕️

odpověď

Dunno o getopt ale getopts builtin lze použít ke zpracování pouze dlouhých možností, jako je tato:

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

Samozřejmě to tak není “ Nefunguje to, pokud mají mít long-options argumenty. Lze to však udělat, ale jak jsem se na tom naučil pracovat. I když jsem to původně zahrnul sem, uvědomil jsem si, že pro dlouhé volby nemá moc užitečnosti. V tomto případě to bylo jen zkrácení mého case (match) pole jediným předvídatelným znakem. Nyní vím, že je vynikající pro krátké volby – je to nejužitečnější, když se smyčka přes řetězec neznámé délky a výběr jednotlivých bytů podle jeho řetězce voleb . Ale když je možnost je arg, není toho moc, co děláš s kombinací for var do case $var in, která by to dokázala. Je to lepší, Myslím si, že je to jednoduché.

Mám podezření, že totéž platí pro getopt, ale nevím o tom dost, abych s jistotou řekl. Vzhledem k následujícímu poli arg předvedu svůj vlastní malý analyzátor arg – který závisí především na vztahu evakuace / přiřazení, který jsem ocenil pro alias a $((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 

S tímto řetězcem arg budu pracovat. Nyní:

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 

Zpracovává pole arg jedním ze dvou různých způsobů podle toho, zda mu předáte jednu nebo dvě sady argumentů oddělených oddělovačem --. V obou případech to platí pro sekvence zpracování do pole arg.

Pokud to nazýváte takto:

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

Jeho první pořadí podnikání bude psát jeho acase() funkci, která bude vypadat takto:

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

A vedle shift 3.Substituce příkazů v definici funkce acase() se vyhodnotí, když volající shell vytvoří vstup této funkce do dokumentů, ale acase() je nikdy nevolán ani definován ve volajícím shellu. Volá se samozřejmě v subshellu, a samozřejmě tímto způsobem můžete dynamicky specifikovat možnosti zájmu na příkazovém řádku.

Pokud jej předáte neomezené pole jednoduše naplní acase() shodami pro všechny argumenty začínající řetězcem --.

Funkce provádí prakticky veškeré své zpracování v subshell – iterativně ukládá každou z hodnot arg do aliasů přiřazených asociativními názvy. Když to projde, vytiskne každou hodnotu, kterou uložila pomocí alias – což je POSIX-specifikovaný pro tisk všech uložených hodnot citovaných takovým způsobem, že jejich hodnoty mohou být znovu vloženy do shellu. Takže když to udělám …

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

Jeho výstup vypadá takto:

...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" 

Při procházení seznamem arg kontroluje shodu bloku případu. Pokud tam najde shodu, hodí příznak – f=optname. Dokud znovu nenajde platnou možnost, přidá každý následující arg do pole, které vytvoří na základě aktuálního příznaku. Pokud je stejná možnost zadána vícekrát, výsledná sloučenina bude přepsána. Cokoli, co není v případě – nebo jakékoli argumenty následující po ignorovaných možnostech – je přiřazeno k ignorovanému poli.

Výstup je zabezpečený pro shell pro automatický vstup shellem, a tak :

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

… by měl být naprosto bezpečný. Pokud to z jakéhokoli důvodu není bezpečné, měli byste pravděpodobně podat hlášení o chybě svému správci prostředí.

Přiřadí každému druhu dvou hodnot aliasů. Nejprve nastaví příznak – k tomu dojde bez ohledu na to, zda volba předchází neshodným argumentům. Takže jakýkoli výskyt --flag v seznamu arg spustí flag=1. To se neslučuje – --flag --flag --flag právě získá flag=1. Tato hodnota se zvyšuje – pro všechny argumenty, které by ji mohly následovat. Může být použit jako indexový klíč. Po provedení eval výše mohu:

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

… získat …

8 1 

A tak:

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 

VÝSTUP

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 

A k argumentům, které se neshodovaly, dosadím ignorované do výše uvedeného for ... in pole, které získá:

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 

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *