Cum se folosește getopt în linia de comandă bash doar cu opțiuni lungi?

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

  • Tu etichetă pentru getopts internă, dar utilizați comanda /usr/bin/getopt.
  • @Anthon Ne pare rău, am folosit eticheta greșită, dar nu am ' nu am suficientă reputație pentru a adăuga o altă etichetă, care are nevoie de 300 de reputații. Cu toate acestea, am șters eticheta greșită chiar acum.

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 și getopt infectează răspunsul dvs.? Începeți cu comentarea getopts apoi menționați doar getopt.
  • @Anthon Tot răspunsul meu este despre programul getopt de la GNU coreutils despre care este întrebarea. I am remediat textul care spunea getopts. Mulțumiri. getopts nu ' nici măcar nu face opțiuni lungi, deci nimic din toate acestea nu se va aplica getopts .
  • 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 

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *