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
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
oggetopt
inficerer til dit svar? Du starter med at kommenteregetopts
og derefter kun nævnegetopt
. - @Anthon Alt mit svar handler om
getopt
-programmet fra GNU coreutils, hvilket er hvad spørgsmålet handler om. Jeg har rettet teksten, der sagdegetopts
. Tak.getopts
gør ikke ' ikke engang lange muligheder, så intet af dette gælder forgetopts
. - 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
getopts
, men du bruger kommandoen/usr/bin/getopt
.