Hur använder man getopt i bash-kommandoraden med bara långa alternativ?

Det finns ett getopt -kommando i bash-kommandoraden. getopt kan användas med korta alternativ (som getopt -o axby "$@") och kan användas med både korta och långa alternativ (som getopt -o axby -l long-key -- "$@"), men nu behöver jag bara långa alternativ (dvs. korta alternativ finns inte alls), men kommandot getopt -l long-key -- "$@" tolkar inte --long-key alternativet korrekt. Så hur kan jag använda getopt -kommandot med endast långa alternativ? Eller är det omöjligt eller är det bara ett fel i kommandot getopt?

Kommentarer

  • Du tagg för den interna getopts, men du använder kommandot /usr/bin/getopt.
  • @Anthon Tyvärr har jag använt fel tagg, men jag har inte ' jag har inte tillräckligt med rykte för att lägga till en ny tagg, som behöver 300 rykte. Jag har dock tagit bort fel tagg just nu.

Svar

getopt är helt bra med inga korta alternativ. Men du måste säga att du inte har några korta alternativ. Det är en konstig syntax – från manualen:

Om inget -o eller --options alternativet finns i den första delen, den första parametern i den andra delen används som korta alternativsträng.

Det är vad som händer i ditt test: getopt -l long-key -- --long-key foo behandlar --long-key som listan över alternativ -egklnoy och foo som enda argument. Använd

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

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

Kommentarer

  • Gjorde OP ' s blandning av getopts och getopt infekterar till ditt svar? Du börjar med att kommentera getopts och bara nämna getopt.
  • @Anthon Allt mitt svar handlar om getopt -programmet från GNU coreutils vilket är vad frågan handlar om. I har fixat texten som säger getopts. Tack. getopts gör ' inte ens långa alternativ, så inget av detta skulle gälla för getopts .
  • OP hade ursprungligen taggen getopts. Jag ville inte ändra ditt svar, för du vet normalt mycket bättre än jag vad du skriver om 🙂
  • Jag tappade nästan en timme och försökte räkna ut det här. Du räddade mig bara några få fåfänga kaffe. Tack … låt oss använda det här kaffet bättre nu. ☕️

Svar

Dunno about getopt men getopts inbyggt kan användas för att hantera bara långa alternativ som detta:

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

Naturligtvis, som det är, gör det inte t fungerar om långa alternativ ska ha argument. Det kan dock göras, men eftersom jag har lärt mig att arbeta med detta. Medan jag ursprungligen inkluderade det här insåg jag att det för långa alternativ inte har mycket nytta. I det här fallet förkortade det bara min case (match) fält med en enda, förutsägbar karaktär. Nu, vad jag vet, är att det är utmärkt för korta alternativ – det är mest användbart när det går över en sträng av okänd längd och väljer enstaka byte enligt dess alternativsträng Men när alternativet är arg, det gör du inte mycket med en for var do case $var in kombination som det skulle kunna göra. Det är bättre, Jag tror, för att hålla det enkelt.

Jag misstänker att samma sak gäller för getopt men jag vet inte tillräckligt om det för att säga med säkerhet. Med tanke på följande arg-array kommer jag att demonstrera min egen lilla arg-parser – som främst beror på utvärderings- / tilldelningsförhållandet jag har uppskattat för alias och $((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 

Det är argsträngen jag kommer att arbeta med. Nu:

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 

Det bearbetar arg-arrayen på ett av två olika sätt beroende på om du ger den en eller två uppsättningar av argument åtskilda av -- avgränsare. I båda fallen gäller det sekvenser för bearbetning till arg-arrayen.

Om du kallar det så:

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

Dess första ordning på verksamheten blir att skriva sin acase() -funktion så att den ser ut:

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

Och bredvid shift 3.Kommandosubstitutionen i acase() funktionsdefinitionen utvärderas när det anropande skalet bygger funktionens inmatning här-dokument, men acase() är aldrig ringt eller definierat i det anropande skalet. Det kallas dock i subshell, naturligtvis, och så kan du dynamiskt ange alternativen av intresse på kommandoraden.

Om du ger det en oavgränsad matris fyller den helt enkelt acase() med matchningar för alla argument som börjar med strängen --.

Funktionen gör praktiskt taget all sin bearbetning i subshell – sparar iterativt vart och ett av arg-värdena i alias tilldelade associerande namn. När det är klart skriver det ut varje värde som sparats med alias – vilket är POSIX-specificerat för att skriva ut alla sparade värden som citeras på ett sådant sätt att deras värden kan matas in i skalet. Så när jag gör …

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

Dess output ser ut så här:

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

När den går igenom arg-listan kontrollerar den mot fallblocket för en match. Om den hittar en match där kastar den en flagga – f=optname. Tills den återigen hittar ett giltigt alternativ kommer den att lägga till varje efterföljande arg till en array som den bygger baserat på den aktuella flaggan. Om samma alternativ anges flera gånger blir resultaten sammansatta och åsidosätter inte. Allt som inte är fallet – eller några argument som följer ignorerade alternativ – tilldelas en ignorerad -matris.

Utgången är skalskyddad för skalinmatning automatiskt av skalet, och så :

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

… borde vara helt säkert. Om det av någon anledning inte är säkert, bör du antagligen skicka en felrapport till din skalhållare.

Den tilldelar två typer av aliasvärden för varje matchning. Först sätter den en flagga – detta inträffar huruvida ett alternativ föregår argument som inte matchar. Så varje förekomst av --flag i arg-listan kommer att utlösa flag=1. Detta förenas inte – --flag --flag --flag blir bara flag=1. Det här värdet ökar dock emellertid – för alla argument som kan följa det. Den kan användas som en indexnyckel. Efter att ha gjort eval ovan kan jag göra:

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

… för att få …

8 1 

Och så:

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 

UTGÅNG

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 

Och till args som inte matchade skulle jag ersätta ignorerad i ovanstående for ... in -fält för att få:

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 

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *