Există o comandă getopt
în linia de comandă bash. getopt
poate fi utilizat cu opțiuni scurte (cum ar fi getopt -o axby "$@"
) și poate fi utilizat atât cu opțiuni scurte, cât și cu opțiuni lungi (cum ar fi getopt -o axby -l long-key -- "$@"
), dar acum am nevoie de numai opțiuni lungi (adică opțiuni scurte nu există deloc), totuși comanda getopt -l long-key -- "$@"
doesn „t parse --long-key
opțiunea corectă. Deci, cum pot folosi comanda getopt
cu opțiuni lungi numai ? Sau este imposibil sau este doar o eroare a comenzii getopt
?
Comentarii
Răspuns
getopt
este perfect dacă nu aveți opțiuni scurte. Dar trebuie să-i spuneți că nu aveți opțiuni scurte. Este „o ciudățenie în sintaxă – din manual:
Dacă nu
-o
sau--options
se găsește în prima parte, primul parametru din a doua parte este folosit ca șir de opțiuni scurte.
Asta se întâmplă în testul dvs.: getopt -l long-key -- --long-key foo
tratează --long-key
ca lista de opțiuni -egklnoy
și foo
ca singur argument. Utilizați
getopt -o "" -l long-key -- "$@"
de ex.
$ 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"
Comentarii
- S-a amestecat OP ' cu
getopts
șigetopt
infectează răspunsul dvs.? Începeți cu comentareagetopts
apoi menționați doargetopt
. - @Anthon Tot răspunsul meu este despre programul
getopt
de la GNU coreutils despre care este întrebarea. I am remediat textul care spuneagetopts
. Mulțumiri.getopts
nu ' nici măcar nu face opțiuni lungi, deci nimic din toate acestea nu se va aplicagetopts
. - OP avea inițial eticheta
getopts
. Nu am vrut să vă schimb răspunsul, deoarece în mod normal știți mult mai bine decât mine despre ce scrieți 🙂 - Am pierdut aproape o oră încercând să-mi dau seama. Tocmai mi-ai salvat câteva înghițituri zadarnice de cafea. Mulțumesc … să folosim acum mai bine această cafea. ☕️
Răspuns
Nu știu despre getopt
, dar getopts
builtin poate fi utilizat pentru a gestiona doar opțiuni lungi ca aceasta:
while getopts :-: o do case "$o$OPTARG" in (-longopt1) process ;; (-longopt2) process ;; esac; done
Desigur, așa este, asta nu face Nu funcționează dacă opțiunile lungi ar trebui să aibă argumente. Se poate face totuși, dar, așa cum am învățat să lucrez la acest lucru. În timp ce l-am inclus inițial aici, mi-am dat seama că pentru opțiunile lungi nu are prea multă utilitate. În acest caz, a fost doar scurtarea case
(match)
câmpuri cu un singur caracter previzibil. Acum, ceea ce știu, este că este excelent pentru opțiuni scurte – este cel mai util atunci când se desfășoară pe un șir de lungime necunoscută și selectează octeți singuri în funcție de opțiunea-șir . Dar când opțiunea este arg, nu faceți prea multe lucruri cu o combinație for var do case $var in
pe care ar putea să o facă. Este mai bine, Cred că, ca să fie simplă.
Bănuiesc că același lucru este valabil și pentru getopt
, dar nu știu suficient despre asta pentru a spune cu certitudine. Având în vedere următoarea matrice arg, voi demonstra propriul meu parser arg – care depinde în primul rând de relația de evaluare / atribuire pe care am ajuns să o apreciez pentru alias
și $((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
Acesta este șirul cu care voi lucra. Acum:
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
Aceasta procesează matricea arg într-unul din cele două moduri diferite, în funcție de faptul dacă îi dați unul sau două seturi de argumente separate prin delimitatorul --
. În ambele cazuri se aplică secvențelor de procesare pentru matricea arg.
Dacă o numiți astfel:
: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"
Prima sa ordine de afacerea va fi să își scrie funcția acase()
pentru a arăta ca:
acase() case "$a" in (--lopt1) f=lopt1; aset "?$(($f)):";; (--lopt2) f=lopt2; aset "?$(($f)):";; (--*) f=ignored; aset "?$(($f)):";; (*) aset "" "$a";;esac
Și lângă shift 3
.Înlocuirea comenzii din definiția funcției acase()
este evaluată atunci când shell-ul apelant construiește documentul introdus aici al funcției, dar acase()
este nu este niciodată apelat sau definit în shell-ul apelant. Acesta este apelat în subshell, totuși, desigur, și astfel puteți specifica dinamic opțiunile de interes pe linia de comandă.
Dacă îi dați un matrice nelimitată pur și simplu populează acase()
cu potriviri pentru toate argumentele care încep cu șirul --
.
Funcția face practic toată procesarea sa în subshell – salvând în mod iterativ fiecare dintre valorile arg în aliasuri atribuite cu nume asociative. Când este finalizat, imprimă fiecare valoare salvată cu alias
– care este specificată POSIX pentru a imprima toate valorile salvate citate în așa fel încât valorile lor să poată fi reintroduse în shell. Deci, când o fac …
aopts --lopt1 --lopt2 -- "$@"
Rezultatul său arată astfel:
...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"
Pe măsură ce parcurge lista arg, verifică blocul de cazuri pentru un meci. Dacă găsește o potrivire acolo, aruncă un steag – f=optname
. Până când va găsi din nou o opțiune validă, va adăuga fiecare argument ulterior la o matrice pe care o construiește pe baza steagului curent. Dacă aceeași opțiune este specificată de mai multe ori rezultatele sunt compuse și nu se anulează. Orice lucru care nu este cazul – sau orice argument care urmează opțiunilor ignorate – sunt atribuite unui tablou ignorat .
Ieșirea este securizată pentru shell-input pentru shell-input automat de către shell, și așa :
eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"
… ar trebui să fie perfect sigur. Dacă, dintr-un motiv sau altul, nu este sigur, atunci ar trebui probabil să înregistrați un raport de erori la administratorul dvs. de shell.
Atribuie două tipuri de valori alias pentru fiecare potrivire. În primul rând, stabilește un semnalizator – aceasta se întâmplă indiferent dacă o opțiune precedă sau nu argumentele care nu se potrivesc. Deci, orice apariție a --flag
în lista arg va declanșa flag=1
. Acest lucru nu se compune – --flag --flag --flag
obține doar flag=1
. Această valoare crește totuși – pentru orice argumente care ar putea să o urmeze. Poate fi folosit ca cheie index. După ce am făcut eval
de mai sus, pot face:
printf %s\\n "$lopt1" "$lopt2"
… pentru a obține …
8 1
Și așa:
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
OUTPUT
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
Și pentru argumentele care nu se potriveau, aș înlocui ignorat în câmpul for ... in
de mai sus pentru a obține:
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
internă, dar utilizați comanda/usr/bin/getopt
.