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
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
agetopt
infikovat vaši odpověď? Začnete komentovánímgetopts
a poté pouze zmínítegetopt
. - @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 nagetopts
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
getopts
, ale používáte příkaz/usr/bin/getopt
.