Hvordan bruges getopt i bash-kommandolinjen med kun lange muligheder?

Der er en getopt kommando i bash-kommandolinjen. getopt kan bruges med korte indstillinger (såsom getopt -o axby "$@") og kan bruges med både korte og lange indstillinger (såsom getopt -o axby -l long-key -- "$@"), men nu har jeg kun brug for lange indstillinger (dvs. korte indstillinger findes slet ikke), men kommandoen getopt -l long-key -- "$@" parser ikke --long-key mulighed korrekt. Så hvordan kan jeg bruge getopt kommando med kun lange indstillinger? Eller er det umuligt, eller er det bare en fejl fra kommandoen getopt?

Kommentarer

  • Dig tag til det interne getopts, men du bruger kommandoen /usr/bin/getopt.
  • @Anthon Undskyld, jeg har brugt det forkerte tag, men jeg har ikke ' Jeg har ikke nok omdømme til at tilføje et nyt tag, der har brug for 300 omdømme. Jeg har dog slettet det forkerte tag lige nu.

Svar

getopt er helt fint med ingen korte muligheder. Men du skal fortælle det, at du ikke har nogen korte muligheder. Det er en finart i syntaksen – fra manualen:

Hvis der ikke er -o eller --options findes i den første del, den første parameter i den anden del bruges som den korte valgstreng.

Det der sker i din test: getopt -l long-key -- --long-key foo behandler --long-key som listen over muligheder -egklnoy og foo som eneste argument. Brug

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

f.eks.

$ 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 blanding af getopts og getopt inficerer til dit svar? Du starter med at kommentere getopts og derefter kun nævne getopt.
  • @Anthon Alt mit svar handler om getopt -programmet fra GNU coreutils, hvilket er hvad spørgsmålet handler om. Jeg har rettet teksten, der sagde getopts. Tak. getopts gør ikke ' ikke engang lange muligheder, så intet af dette gælder for getopts .
  • OP havde oprindeligt getopts -tagget. Jeg ville ikke ændre dit svar, fordi du normalt ved meget bedre end jeg, hvad du skriver om 🙂
  • Jeg tabte næsten en time på at prøve at finde ud af dette. Du har lige sparet mig et par forgæves kaffe. Tak … lad os bruge denne kaffe til en bedre brug nu. ☕️

Svar

Dunno om getopt men getopts builtin kan kun bruges til at håndtere lange indstillinger som denne:

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

Selvfølgelig, som det er, gør det ikke ” t arbejde, hvis de lange muligheder skal have argumenter. Det kan dog gøres, men som jeg har lært at arbejde på dette. Mens jeg oprindeligt inkluderede det her, indså jeg, at det for lange muligheder ikke har meget nyttigt. I dette tilfælde forkortede det kun min case (match) felter med et enkelt, forudsigeligt tegn. Nu, hvad jeg ved, er, at det er fremragende til korte indstillinger – det er mest nyttigt, når det løber over en streng af ukendt længde og vælger enkelt byte i henhold til sin valgstreng Men når indstillingen er arg, er der ikke meget, du laver med en for var do case $var in kombination, som den kunne gøre. Det er bedre, Jeg tror, for at holde det enkelt.

Jeg formoder, at det samme gælder for getopt men jeg ved ikke nok om det til at sige med sikkerhed. I lyset af følgende arg-array vil jeg demonstrere min egen lille arg-parser – som primært afhænger af evaluerings- / tildelingsforholdet, jeg har set at værdsætte for alias og $((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 er argstrengen, jeg vil arbejde 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 behandler arg-arrayet på en af to forskellige måder, afhængigt af om du giver det et eller to sæt argumenter adskilt af -- -afgrænseren. I begge tilfælde gælder det for behandlingssekvenser til arg-arrayet.

Hvis du kalder det sådan:

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

Dens første rækkefølge på forretning vil være at skrive sin acase() -funktion for at ligne:

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

Og ved siden af shift 3.Kommandosubstitutionen i funktionsdefinitionen acase() evalueres, når den kaldende shell bygger funktionens input her-dokumenter, men acase() er aldrig kaldt eller defineret i den kaldende skal. Det kaldes selvfølgelig selvfølgelig i subshell, og på denne måde kan du dynamisk angive de interessante indstillinger på kommandolinjen.

Hvis du giver det en un-afgrænset array det udfylder simpelthen acase() med matches for alle argumenter, der begynder med strengen --.

Funktionen udfører praktisk talt al sin behandling i subshell – gemmer iterativt hver af arg-værdierne til aliaser tilknyttet associerende navne. Når det er igennem, udskriver den hver værdi, den gemte med alias – som er POSIX-specificeret til at udskrive alle de gemte værdier, der er citeret på en sådan måde, at deres værdier kan genindføres til skallen. Så når jeg gør …

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

Dens output ser sådan ud:

...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 gennem arg-listen, kontrollerer den mod sagsblokken for en kamp. Hvis den finder en match der, kaster den et flag – f=optname. Indtil den igen finder en gyldig mulighed, tilføjer den hver efterfølgende arg til et array, den bygger baseret på det aktuelle flag. Hvis den samme mulighed er angivet flere gange, sammensættes resultaterne og tilsidesætter ikke. Alt, hvad der ikke er tilfældet – eller argumenter, der følger ignorerede indstillinger – tildeles et ignoreret array.

Outputtet er shell-beskyttet til shell-input automatisk af shell, og så :

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

… skal være helt sikkert. Hvis det af en eller anden grund ikke er sikkert, skal du sandsynligvis indsende en fejlrapport med din shell-vedligeholder.

Den tildeler to slags aliasværdier for hvert match. For det første sætter det et flag – dette sker, uanset om en mulighed går forud for ikke-matchende argumenter. Så enhver forekomst af --flag i arg-listen udløser flag=1. Dette sammensættes ikke – --flag --flag --flag får bare flag=1. Denne værdi stiger dog – for alle argumenter, der måtte følge den. Det kan bruges som en indeksnøgle. Efter at have udført eval ovenfor kan jeg gøre:

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

… for at få …

8 1 

Og 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 

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 

Og til args, der ikke matchede, ville jeg erstatte ignoreret i ovenstående for ... in -felt for at 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 

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *