Bash-komentorivillä on getopt
-komento. getopt
voidaan käyttää lyhyillä vaihtoehdoilla (kuten getopt -o axby "$@"
), ja sitä voidaan käyttää sekä lyhyiden että pitkien vaihtoehtojen kanssa (kuten getopt -o axby -l long-key -- "$@"
), mutta nyt tarvitsen vain pitkiä vaihtoehtoja (ts. lyhyitä vaihtoehtoja ei ole ollenkaan), mutta komento getopt -l long-key -- "$@"
doesn ”t jäsentää --long-key
-vaihtoehdon oikein. Joten miten voin käyttää komentoa getopt
vain pitkillä vaihtoehdoilla? Vai onko se mahdotonta, vai onko se vain vika getopt
-komennossa?
Kommentit
Vastaa
getopt
on täysin hieno ilman lyhyitä vaihtoehtoja. Mutta sinun on kerrottava sille, että sinulla ei ole lyhyitä vaihtoehtoja. Se on omituinen syntaksissa – käsikirjasta:
Jos ei
-o
tai--options
-vaihtoehto löytyy ensimmäisestä osasta, toisen osan ensimmäistä parametria käytetään lyhyenä vaihtoehtojen merkkijonona.
Sitä mitä testissä tapahtuu: getopt -l long-key -- --long-key foo
käsittelee --long-key
vaihtoehtoluettelona -egklnoy
ja foo
ainoana argumenttina. Käytä
getopt -o "" -l long-key -- "$@"
esim.
$ 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"
Kommentit
- Sekoittiko OP ' sekoittamalla
getopts
jagetopt
tartuttaa vastauksesi? Aloitat kommentoinnillagetopts
ja mainitset sitten vaingetopt
. - @Anthon Kaikki vastaukseni koskee
getopt
-ohjelmaa GNU coreutilsista, mistä kysymys onkin. I ve korjattu teksti, joka sanoigetopts
. Kiitos.getopts
ei ' edes tee pitkiä vaihtoehtoja, joten mikään näistä ei koskegetopts
. - OP: lla oli alun perin
getopts
-tunniste. En halunnut muuttaa vastaustasi, koska tiedät yleensä paljon paremmin kuin minä, mistä kirjoitat 🙂 - Menetin melkein tunnin yrittäessäni selvittää tämän. Säästit vain muutaman turhaan kahvia. Kiitos … antaa tämän kahvin käyttää paremmin. ☕️
Vastaa
Älä tiedä getopt
-kohdasta, mutta getopts
sisäänrakennettua voidaan käyttää vain tällaisten pitkien vaihtoehtojen käsittelemiseen:
while getopts :-: o do case "$o$OPTARG" in (-longopt1) process ;; (-longopt2) process ;; esac; done
Tietysti, kuten ei, niin ei ” Ei toimi, jos pitkillä vaihtoehdoilla oletetaan olevan argumentteja. Se voidaan kuitenkin tehdä, mutta kuten olen oppinut työskentelemään tämän kanssa. Vaikka sisällytin sen alun perin tähän, huomasin, että pitkillä vaihtoehdoilla sillä ei ole paljon hyötyä. Tässä tapauksessa se vain lyhensi case
(match)
-kentät yhdellä, ennakoitavalla merkillä. Tiedän nyt, että se sopii erinomaisesti lyhyille vaihtoehdoille – se on hyödyllisin, kun se silmukkaa tuntemattoman pituisen merkkijonon yli ja valitsee yksittäisiä tavuja option-merkkijonon mukaan . Mutta kun vaihtoehto on arg, ei ole paljon tekemistä for var do case $var in
-yhdistelmällä, jonka se voisi tehdä. On parempi, Luulen, että yksinkertaisuus.
Epäilen, että sama pätee getopt
, mutta en tiedä siitä tarpeeksi sanoa varmuudella. Seuraavan arg-taulukon perusteella esitän oman pienen arg-jäsentimen – joka riippuu ensisijaisesti arviointi / määrityssuhteesta, jota olen arvostanut alias
ja $((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
Se on arg-merkkijono, jonka kanssa työskentelen. Nyt:
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
Se käsittelee arg-taulukon kahdella eri tavalla riippuen siitä, annatko sille yhden vai kaksi argumenttisarjaa, jotka on erotettu --
-erottimella. Molemmissa tapauksissa se koskee arg-taulukon käsittelysekvenssejä.
Jos kutsutaan sitä näin:
: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"
Sen ensimmäinen järjestys Yrityksen on kirjoitettava acase()
-funktionsa näyttämään tältä:
acase() case "$a" in (--lopt1) f=lopt1; aset "?$(($f)):";; (--lopt2) f=lopt2; aset "?$(($f)):";; (--*) f=ignored; aset "?$(($f)):";; (*) aset "" "$a";;esac
Ja vieressä shift 3
.Komennon korvaaminen funktion acase()
määritelmässä arvioidaan, kun kutsuva kuori rakentaa funktion syötteen tähän-dokumentit, mutta acase()
on ei koskaan kutsuttu tai määritelty kutsuvassa kuoressa. Sitä kutsutaan tietysti alikuoressa, joten tällä tavalla voit määrittää dynaamisesti kiinnostavat vaihtoehdot komentorivillä.
Jos annat sille rajoittamaton taulukko se vain täyttää acase()
vastaavuudet kaikille argumenteille, jotka alkavat merkkijonolla --
.
Funktio tekee käytännössä kaiken prosessoinnin alikuoressa – säästää iteratiivisesti kutakin argin arvoa aliaksiksi, jotka liitetään assosiatiivisiin nimiin. Kun se on läpi, tulostaa kaikki arvot, jotka se on tallentanut tiedostolla alias
– joka on POSIX-määritelty tulostamaan kaikki mainitut tallennetut arvot siten, että niiden arvot voidaan palauttaa komentotulkkiin. Joten kun teen …
aopts --lopt1 --lopt2 -- "$@"
Sen tulos näyttää tältä:
...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"
Käydessään arg-luetteloa se tarkistaa ottelun tapauslohkon. Jos se löytää ottelun, se heittää lipun – f=optname
. Kunnes se löytää jälleen kelvollisen vaihtoehdon, se lisää jokaisen seuraavan argin matriisiin, jonka se rakentaa nykyisen lipun perusteella. Jos sama vaihtoehto määritetään useita kertoja, tulosyhdistelmä ei ohita. Kaikki, mitä ei ole, tai mikä tahansa argumentti, joka seuraa ohitettuja vaihtoehtoja, määritetään ohitetulle taulukolle.
Lähtö on suojattu kuorelle kuoren syöttöä varten kuoren toimesta automaattisesti. :
eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"
… pitäisi olla täysin turvallinen. Jos se jostain syystä ei ole turvallinen, sinun on todennäköisesti toimitettava virheraportti kuoren ylläpitäjälle.
Se määrittää kahden tyyppisen aliaksen arvon kullekin ottelulle. Ensinnäkin se asettaa lipun – tämä tapahtuu riippumatta siitä, onko vaihtoehto edeltävä argumentteja, jotka eivät täsmää. Joten mikä tahansa --flag
: n esiintyminen arg-luettelossa laukaisee flag=1
. Tämä ei muodosta yhdistelmää – --flag --flag --flag
saa vain flag=1
. Tämä arvo lisää kuitenkin kasvua – kaikille argumenteille, jotka saattavat seurata sitä. Sitä voidaan käyttää hakemistoavaimena. Suoritettuani yllä olevan eval
-kohdan voin:
printf %s\\n "$lopt1" "$lopt2"
… saada …
8 1
Ja niin:
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
Ja argumentteihin, jotka eivät vastanneet, korvaan ohitettu yllä olevassa for ... in
-kentässä saadaksesi:
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
-tunnisteen, mutta käytät komentoa/usr/bin/getopt
.