Hoe gebruik je getopt in de bash-opdrachtregel met alleen lange opties?

Er is een getopt commando in de bash command line. getopt kan worden gebruikt met korte opties (zoals getopt -o axby "$@"), en kan worden gebruikt met zowel korte als lange opties (zoals getopt -o axby -l long-key -- "$@"), maar nu heb ik alleen lange opties nodig (dwz korte opties bestaan helemaal niet), maar het commando getopt -l long-key -- "$@" ontleedt de optie --long-key niet correct. Dus hoe kan ik het getopt commando gebruiken met alleen lange opties? Of is het onmogelijk of is het gewoon een bug van het getopt commando?

Reacties

  • Jij tag voor de interne getopts, maar je gebruikt het /usr/bin/getopt commando.
  • @Anthon Sorry, ik heb gebruikt de verkeerde tag, maar ik heb ' niet genoeg reputaties om een andere tag toe te voegen, die 300 reputaties nodig heeft. Ik heb echter zojuist de verkeerde tag verwijderd.

Antwoord

getopt is prima zonder korte opties. Maar je moet hem vertellen dat je geen korte opties hebt. Het is een eigenaardigheid in de syntaxis – uit de handleiding:

Indien geen -o of --options optie is te vinden in het eerste deel, de eerste parameter van het tweede deel wordt gebruikt als de korte tekenreeks voor opties.

Dat is wat er gebeurt in uw test: getopt -l long-key -- --long-key foo behandelt --long-key als de lijst met opties -egklnoy en foo als het enige argument. Gebruik

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

bijv.

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

Reacties

  • Heeft het OP ' s mixen van getopts en getopt besmetten je antwoord? Je begint met commentaar getopts en noem dan alleen getopt.
  • @Anthon Al mijn antwoord gaat over het getopt programma van GNU coreutils en daar gaat de vraag over. I hebben de tekst gerepareerd die getopts zei. Bedankt. getopts doet ' zelfs geen lange opties, dus dit zou niet van toepassing zijn op getopts .
  • Het OP had oorspronkelijk de tag getopts. Ik wilde je antwoord niet veranderen, omdat je normaal gesproken veel beter weet dan ik waar je over schrijft 🙂
  • Ik heb bijna een uur verloren om dit uit te zoeken. Je hebt me zojuist een paar ijdele koffie slokjes bespaard. Bedankt … laten we deze koffie nu beter gebruiken. ☕️

Antwoord

Weet niet over getopt maar de getopts ingebouwd kan worden gebruikt om alleen lange opties als volgt af te handelen:

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

Natuurlijk, zoals het is, dat niet ” Het werkt niet als de lange opties argumenten moeten hebben. Het kan wel, maar zoals ik heb geleerd hieraan te werken. Terwijl ik het hier aanvankelijk opnam, realiseerde ik me dat het voor lange opties niet “veel nut heeft. In dit geval was het alleen maar mijn case (match) velden door een enkel, voorspelbaar karakter. Wat ik nu weet, is dat het uitstekend geschikt is voor korte opties – het is vooral handig wanneer het een reeks van onbekende lengte doorloopt en enkele bytes selecteert op basis van de optie-reeks . Maar als de optie is de arg, “doe je niet veel met een for var do case $var in combinatie die het zou kunnen doen. Het is beter, Ik denk, om het simpel te houden.

Ik vermoed dat hetzelfde geldt voor getopt, maar ik weet er niet genoeg van af om met enige zekerheid te zeggen. Gegeven de volgende arg-array, zal ik mijn eigen kleine arg-parser demonstreren – die voornamelijk afhangt van de evaluatie / toewijzingsrelatie die ik “ben gaan waarderen voor alias en $((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 

Dat is de arg-string waarmee ik zal werken. 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 

Dat verwerkt de arg-array op een van twee verschillende manieren, afhankelijk van of je het een of twee sets argumenten geeft, gescheiden door het -- scheidingsteken. In beide gevallen is het van toepassing op reeksen van verwerking naar de arg-array.

Als je het noemt als:

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

De eerste volgorde van zaken zullen zijn om zijn acase() functie te schrijven om er als volgt uit te zien:

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

En naast shift 3.De opdrachtsubstitutie in de acase() functiedefinitie wordt geëvalueerd wanneer de aanroepende shell de functie “s invoer hier-documenten bouwt, maar acase() is nooit aangeroepen of gedefinieerd in de aanroepende shell. Het wordt natuurlijk wel in de subshell aangeroepen en op deze manier kun je dynamisch de opties van belang specificeren op de opdrachtregel.

Als je het een niet-gescheiden array, het vult eenvoudig acase() met overeenkomsten voor alle argumenten die beginnen met de tekenreeks --.

De functie doet praktisch al zijn verwerking in de subshell – iteratief slaat elk van de arg-waarden op in aliassen die zijn toegewezen aan associatieve namen. Als het klaar is, drukt het elke waarde af die het heeft opgeslagen met alias – die POSIX-gespecificeerd is om alle opgeslagen waarden op zon manier af te drukken dat hun waarden opnieuw in de shell kunnen worden ingevoerd. Dus als ik dat doe …

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

De uitvoer ziet er als volgt uit:

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

Terwijl het door de arg-lijst loopt, controleert het aan de hand van het case-blok voor een match. Als het daar een overeenkomst vindt, wordt er een vlag gegooid – f=optname. Totdat het opnieuw een geldige optie vindt, zal het elk volgend argument toevoegen aan een array die het bouwt op basis van de huidige vlag. Als dezelfde optie meerdere keren is opgegeven, worden de resultaten samengesteld en niet overschreven. Alles wat niet in het geval is – of alle argumenten die volgen op genegeerde opties – wordt toegewezen aan een genegeerde array.

De uitvoer wordt automatisch shell-veilig gemaakt voor shell-invoer door de shell, en zo :

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

… zou volkomen veilig moeten zijn. Als het om welke reden dan ook niet veilig is, dan zou je waarschijnlijk een bugrapport moeten indienen bij je shell-onderhouder.

Het wijst twee soorten aliaswaarden toe voor elke overeenkomst. Ten eerste stelt het een vlag in – dit gebeurt ongeacht of een optie voorafgaat aan niet-overeenkomende argumenten. Dus elk voorkomen van --flag in de arg-lijst zal flag=1 activeren. Dit maakt geen verbinding – --flag --flag --flag krijgt alleen flag=1. Deze waarde doet echter toenemen – voor alle argumenten die erop kunnen volgen. Het kan worden gebruikt als een indexsleutel. Na het uitvoeren van de eval hierboven kan ik doen:

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

… om …

8 1 

En zo:

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 

En voor args die niet overeenkwamen zou ik genegeerd vervangen in het bovenstaande for ... in veld om te krijgen:

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 

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *