Saya ingin memiliki bentuk panjang dan pendek opsi baris perintah dipanggil menggunakan skrip shell saya.
Saya tahu itu getopts
bisa digunakan, tetapi seperti di Perl, saya belum bisa melakukan hal yang sama dengan shell.
Ada ide tentang bagaimana hal ini dapat dilakukan, sehingga saya dapat menggunakan opsi seperti:
./shell.sh --copyfile abc.pl /tmp/
./shell.sh -c abc.pl /tmp/
Di atas, kedua perintah memiliki arti yang sama untuk shell saya, tetapi menggunakan getopts
, saya belum bisa mengimplementasikan ini?
bash
command-line-arguments
getopt
getopts
gagneet
sumber
sumber
Jawaban:
Ada tiga implementasi yang dapat dipertimbangkan:
Bash builtin
getopts
. Ini tidak mendukung nama opsi panjang dengan awalan dasbor ganda. Ini hanya mendukung opsi karakter tunggal.BSD UNIX implementasi
getopt
perintah mandiri (yang digunakan MacOS). Ini juga tidak mendukung opsi panjang.Implementasi mandiri GNU
getopt
. GNUgetopt(3)
(digunakan oleh command-linegetopt(1)
di Linux) mendukung parsing opsi panjang.Beberapa jawaban lain menunjukkan solusi untuk menggunakan bash builtin
getopts
untuk meniru opsi yang panjang. Solusi itu sebenarnya membuat opsi pendek yang karakternya "-". Jadi Anda mendapatkan "-" sebagai bendera. Lalu apa pun yang mengikuti yang menjadi OPTARG, dan Anda menguji OPTARG dengan bersarangcase
.Ini pintar, tetapi disertai dengan peringatan:
getopts
tidak dapat memberlakukan spec opt. Itu tidak dapat mengembalikan kesalahan jika pengguna memberikan opsi yang tidak valid. Anda harus melakukan pengecekan kesalahan sendiri saat mengurai OPTARG.Jadi, walaupun dimungkinkan untuk menulis lebih banyak kode untuk mengatasi kurangnya dukungan untuk opsi panjang, ini jauh lebih banyak pekerjaan dan sebagian mengalahkan tujuan menggunakan parser getopt untuk menyederhanakan kode Anda.
sumber
getopt
dangetopts
binatang buas yang berbeda, dan orang-orang tampaknya memiliki sedikit kesalahpahaman tentang apa yang mereka lakukan.getopts
adalah perintah bawaan untukbash
memroses opsi baris perintah dalam satu lingkaran dan menetapkan masing-masing opsi dan nilai yang ditemukan pada gilirannya ke variabel bawaan, sehingga Anda dapat memprosesnya lebih lanjut.getopt
, bagaimanapun, adalah program utilitas eksternal, dan itu tidak benar-benar memproses pilihan Anda untuk Anda seperti yang dilakukan oleh bashgetopts
,Getopt
modul Perl atau Pythonoptparse
/argparse
modules. Semua yanggetopt
dilakukan adalah mengkanonik opsi yang diteruskan - yaitu mengonversikannya ke bentuk yang lebih standar, sehingga lebih mudah bagi skrip shell untuk memprosesnya. Misalnya, aplikasigetopt
mungkin mengonversi yang berikut:dalam hal ini:
Anda harus melakukan pemrosesan aktual sendiri. Anda tidak harus menggunakan
getopt
sama sekali jika Anda membuat berbagai batasan pada cara Anda dapat menentukan opsi:-o
atas), nilainya harus sebagai argumen terpisah (setelah spasi).Kenapa menggunakan
getopt
bukangetopts
? Alasan dasarnya adalah hanya GNU yanggetopt
memberi Anda dukungan untuk opsi baris perintah yang telah lama dinamai. 1 (GNUgetopt
adalah default di Linux. Mac OS X dan FreeBSD datang dengan dasar dan tidak terlalu bergunagetopt
, tetapi versi GNU dapat diinstal; lihat di bawah.)Sebagai contoh, berikut adalah contoh penggunaan GNU
getopt
, dari skrip saya yang bernamajavawrap
:Ini memungkinkan Anda menentukan opsi suka
--verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"
atau serupa. Efek dari panggilan kegetopt
adalah untuk mengkanoniskan opsi--verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"
agar Anda dapat memprosesnya dengan lebih mudah. Mengutip sekitar"$1"
dan"$2"
penting karena memastikan bahwa argumen dengan spasi di dalamnya ditangani dengan benar.Jika Anda menghapus 9 baris pertama (semuanya naik melalui
eval set
baris), kodenya akan tetap berfungsi ! Namun, kode Anda akan lebih pemilih dalam jenis opsi apa yang diterimanya: Khususnya, Anda harus menentukan semua opsi dalam formulir "kanonik" yang dijelaskan di atas.getopt
Namun, dengan penggunaan , Anda dapat mengelompokkan opsi huruf tunggal, menggunakan bentuk opsi panjang yang tidak ambigu yang lebih pendek, menggunakan salah satu--file foo.txt
atau--file=foo.txt
gaya, menggunakan salah satu-m 4096
atau-m4096
gaya, menggunakan opsi atau gaya, mencampur pilihan dan non-opsi dalam urutan apa pun, dll.getopt
juga menampilkan pesan kesalahan jika opsi tidak dikenal atau ambigu ditemukan.CATATAN : Sebenarnya ada dua versi yang sangat berbeda
getopt
, dasargetopt
dan GNUgetopt
, dengan fitur yang berbeda dan konvensi panggilan yang berbeda. 2 Basicgetopt
cukup rusak: Tidak hanya tidak menangani opsi yang panjang, tetapi juga tidak bisa menangani ruang yang disematkan di dalam argumen atau argumen kosong, sedangkangetopts
melakukan ini dengan benar. Kode di atas tidak akan berfungsi di dasargetopt
. GNUgetopt
diinstal secara default di Linux, tetapi pada Mac OS X dan FreeBSD perlu diinstal secara terpisah. Di Mac OS X, instal MacPorts ( http://www.macports.org ) dan kemudian lakukansudo port install getopt
untuk menginstal GNUgetopt
(biasanya ke/opt/local/bin
), dan pastikan itu/opt/local/bin
ada di jalur shell Anda di depan/usr/bin
. Di FreeBSD, instalmisc/getopt
.Panduan cepat untuk memodifikasi kode contoh untuk program Anda sendiri: Dari beberapa baris pertama, semua adalah "boilerplate" yang harus tetap sama, kecuali baris yang memanggil
getopt
. Anda harus mengubah nama program setelah-n
, tentukan opsi pendek setelah-o
, dan opsi panjang setelah--long
. Beri tanda titik dua setelah opsi yang mengambil nilai.Akhirnya, jika Anda melihat kode yang baru saja
set
bukaneval set
, itu ditulis untuk BSDgetopt
. Anda harus mengubahnya untuk menggunakaneval set
gaya, yang berfungsi dengan baik dengan kedua versigetopt
, sementara polosset
tidak berfungsi dengan baik dengan GNUgetopt
.1 Sebenarnya,
getopts
dalamksh93
mendukung opsi yang telah lama dinamai, tetapi shell ini tidak digunakan seseringbash
. Dizsh
, gunakanzparseopts
untuk mendapatkan fungsi ini.2 Secara teknis, "GNU
getopt
" adalah istilah yang salah; versi ini sebenarnya ditulis untuk Linux daripada proyek GNU. Namun, ia mengikuti semua konvensi GNU, dan istilah "GNUgetopt
" umumnya digunakan (misalnya pada FreeBSD).sumber
getopt
di Linux bukan utilitas GNU dan tradisionalgetopt
tidak awalnya berasal dari BSD tetapi dari AT&T Unix. ksh93getopts
(juga dari AT&T) mendukung opsi panjang bergaya GNU.POSIXLY_CORRECT
), sementara "Linux-enhanced getopt" secara salah menunjukkan bahwa versi ini hanya ada di Linux.getopt
bisa dengan mudah diporting ke Unix lain, tetapi banyak perangkat lunak lainutil-linux
yang khusus untuk Linux). Semua program non-GNU yang memanfaatkan GNU getopt (3) mengerti$POSIX_CORRECT
. Misalnya, Anda tidak akan mengatakan ituaplay
GNU hanya dengan alasan itu. Saya menduga bahwa ketika FreeBSD menyebutkan GNU getopt, artinya GNU getopt (3) C API.getopt
util, bukan getopt (3).Fungsi getash bawaan Bash dapat digunakan untuk mem-parsing opsi-opsi panjang dengan meletakkan karakter tanda hubung diikuti oleh titik dua ke dalam optspec:
Setelah menyalin ke nama file yang dapat dieksekusi =
getopts_test.sh
di direktori kerja saat ini , orang dapat menghasilkan output sepertiJelas getopts tidak melakukan
OPTERR
pemeriksaan atau penguraian opsi-argumen untuk opsi yang panjang. Fragmen skrip di atas menunjukkan bagaimana hal ini dapat dilakukan secara manual. Prinsip dasar juga bekerja di shell Debian Almquist ("dash"). Perhatikan kasus khusus:Perhatikan bahwa, seperti yang ditunjukkan GreyCat dari http://mywiki.wooledge.org/BashFAQ , trik ini mengeksploitasi perilaku non-standar dari shell yang memungkinkan opsi-argumen (yaitu nama file dalam "-f nama file") untuk digabungkan dengan opsi (seperti dalam "-filename"). Standar POSIX mengatakan harus ada ruang di antara mereka, yang dalam kasus "- longoption" akan mengakhiri parsing opsi dan mengubah semua longoptions menjadi argumen non-opsi.
sumber
!
dival="${!OPTIND}
?getopts
secara otomatis hanya menambahOPTIND
dengan 1, tetapi dalam kasus kami, kami memerlukannya untuk menambah 2, jadi kami menambahnya dengan 1 secara manual, lalu membiarkannyagetopts
bertambah 1 lagi untuk kami secara otomatis.$
perlu.OPTIND=$(( $OPTIND + 1 ))
bisa adilOPTIND=$(( OPTIND + 1 ))
. Yang lebih menarik lagi, Anda bahkan dapat menetapkan dan meningkatkan variabel di dalam ekspresi aritmatika, sehingga dimungkinkan untuk menyingkatnya lebih jauh: $(( ++OPTIND ))
, atau bahkan(( ++OPTIND ))
mempertimbangkan yang++OPTIND
akan selalu positif, sehingga tidak akan meningkatkan shell run dengan-e
opsi. :-) gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html--very-bad
memberi peringatan?Built-in
getopts
command masih, AFAIK, terbatas pada pilihan karakter tunggal saja.Ada (atau dulu) program eksternal
getopt
yang akan mengatur ulang serangkaian opsi sedemikian rupa sehingga lebih mudah diurai. Anda dapat menyesuaikan desain itu untuk menangani opsi yang panjang juga. Contoh penggunaan:Anda dapat menggunakan skema serupa dengan a
getoptlong
perintah.Perhatikan bahwa kelemahan mendasar dengan
getopt
program eksternal adalah sulitnya menangani argumen dengan spasi di dalamnya, dan dalam menjaga ruang-ruang tersebut secara akurat. Inilah sebabnya mengapa built-ingetopts
lebih unggul, meskipun dibatasi oleh fakta bahwa itu hanya menangani opsi huruf tunggal.sumber
eval set
dengan tanda kutip (lihat jawaban saya di bawah) sehingga juga bekerja dengan benar dengan GNU getopt (default di Linux) dan menangani spasi dengan benar.${1+"$@"}
aneh dan bertentangan dengan apa yang diperlukan dalam shell modern dan khususnya dengan shell apa pun yang Anda temukan di Linux. Lihat Menggunakan $ 1: + "$ @"} di / bin / sh untuk pembahasan notasi itu.)eval set
melakukan hal yang benar dengan GNU dan BSDgetopt
, sedangkan plainset
hanya melakukan hal yang benar dengan BSDgetopt
. Jadi sebaiknya Anda gunakaneval set
untuk mendorong orang agar terbiasa melakukan hal ini. Terima kasih BTW, saya tidak menyadari bahwa${1+"$@"}
itu tidak diperlukan lagi. Saya harus menulis hal-hal yang berfungsi baik di Mac OS X dan Linux - di antara keduanya, mereka memaksa banyak portabilitas. Aku hanya memeriksa dan"$@"
memang melakukan hal yang benar pada semuash
,bash
,ksh
, danzsh
di bawah Mac OS X; pasti di Linux juga.Berikut ini contoh yang benar-benar menggunakan getopt dengan opsi panjang:
sumber
eval set
dengan tanda kutip (lihat jawaban saya di bawah) sehingga ini juga berfungsi dengan benar dengan GNU getopt (default di Linux) dan menangani spasi dengan benar.getopt
sementara pertanyaannya adalah tentanggetopts
.(--
,(-*
dan(*
pola yang valid? Bagaimana mereka berbeda--
,-*
dan*
?(--)
identik dengan--)
dalamcase
bait. Sungguh aneh melihat lekukan yang tidak rata dan penggunaan yang tidak konsisten dari parensa pilihan opsional, tetapi kode jawaban saat ini terlihat valid bagi saya.Opsi panjang dapat diuraikan oleh standar
getopts
bawaan sebagai "argumen" ke-
"opsi"Ini adalah shell POSIX portabel dan asli - tidak diperlukan program eksternal atau bashisme.
Ini panduan alat pilihan selama argumen dengan
-
pilihan, sehingga--alpha
dipandang olehgetopts
karena-
dengan argumenalpha
dan--bravo=foo
dipandang sebagai-
dengan argumenbravo=foo
. Argumen benar dapat dipanen dengan penggantian sederhana:${OPTARG#*=}
.Dalam contoh ini,
-b
dan-c
(dan bentuknya yang panjang,--bravo
dan--charlie
) memiliki argumen wajib. Argumen untuk opsi panjang datang setelah tanda sama dengan, misalnya--bravo=foo
(pembatas ruang untuk opsi panjang akan sulit untuk diterapkan, lihat di bawah).Karena ini menggunakan
getopts
builtin , solusi ini mendukung penggunaan seperticmd --bravo=foo -ac FILE
(yang memiliki opsi gabungan-a
dan-c
dan interleave opsi panjang dengan opsi standar) sementara sebagian besar jawaban lain di sini berjuang atau gagal melakukannya.Ketika opsi adalah tanda hubung (
-
), itu adalah opsi yang panjang.getopts
akan mem-parsing opsi panjang aktual ke$OPTARG
, misalnya--bravo=foo
set awalOPT='-'
danOPTARG='bravo=foo'
. Theif
bait set$OPT
dengan isi$OPTARG
sebelum equals tanda pertama (bravo
dalam contoh kita) dan kemudian menghapus yang dari awal$OPTARG
(menghasilkan=foo
dalam langkah ini, atau string kosong jika tidak ada=
). Akhirnya, kami menghapus argumen yang utama=
. Pada titik ini,$OPT
ada opsi pendek (satu karakter) atau opsi panjang (2+ karakter).The
case
kemudian cocok baik pendek atau opsi panjang. Untuk opsi pendek,getopts
secara otomatis mengeluh tentang opsi dan argumen yang hilang, jadi kami harus mereplikasi mereka secara manual menggunakanneeds_arg
fungsi, yang secara fatal keluar ketika$OPTARG
kosong. The??*
Kondisi akan ditemukan sisa opsi panjang (?
cocok dengan karakter tunggal dan*
pertandingan nol atau lebih, sehingga??*
cocok 2+ karakter), memungkinkan kita untuk mengeluarkan error "pilihan Ilegal" sebelum keluar.(Catatan tentang semua nama variabel huruf besar: Secara umum, sarannya adalah untuk mencadangkan semua variabel huruf besar untuk penggunaan sistem. Saya tetap
$OPT
menggunakan huruf besar semua untuk tetap sejalan$OPTARG
, tapi ini melanggar konvensi itu. Saya pikir itu cocok karena ini adalah sesuatu yang seharusnya dilakukan sistem, dan harus aman karena tidak ada standar (afaik) yang menggunakan variabel seperti itu.)Untuk mengeluh tentang argumen tak terduga ke opsi panjang, meniru apa yang kami lakukan untuk argumen wajib: gunakan fungsi pembantu. Balik saja tes untuk mengeluh tentang argumen ketika seseorang tidak diharapkan:
Versi yang lebih lama dari jawaban ini berupaya menerima opsi panjang dengan argumen terbatas-ruang, tetapi tidak dapat diandalkan;
getopts
bisa secara prematur berakhir dengan asumsi bahwa argumen itu di luar cakupannya dan penambahan secara manual$OPTIND
tidak berfungsi di semua shell.Ini akan dicapai dengan menggunakan salah satu dari teknik ini:
eval "bravo=\"\$$OPTIND\""
bravo="${!OPTIND}"
P
Zsh :bravo="${(P)OPTIND}"
dan kemudian menyimpulkan dengan sesuatu seperti
[ $# -gt $OPTIND ] && OPTIND=$((OPTIND+1))
sumber
letter-c
tidak memerlukan argumen, apakah itu tidak cukup untuk digunakanletter-c)
? yang*
tampaknya berlebihan.getopts
berhenti pada argumen posisi pertama karena tidak dirancang untuk menghadapinya. Ini memungkinkan sub-perintah dengan argumen mereka sendiri, misalnyagit diff --color
, jadi saya akan menafsirkancommand --foo=moo bar --baz waz
sebagai memiliki--foo
argumencommand
dan--baz waz
sebagai argumen (dengan opsi) kebar
sub-perintah. Ini dapat dilakukan dengan kode di atas. Saya menolak--bravo -blah
karena--bravo
membutuhkan argumen dan tidak jelas bahwa-blah
itu bukan pilihan lain.eval
dalam shell POSIX, itu terdaftar di bawah sisa jawabannya.Lihatlah shFlags yang merupakan pustaka shell portabel (artinya: sh, bash, dash, ksh, zsh di Linux, Solaris, dll.).
Itu membuat menambahkan bendera baru sesederhana menambahkan satu baris ke skrip Anda, dan menyediakan fungsi penggunaan yang dihasilkan secara otomatis.
Berikut adalah shFlag sederhana yang
Hello, world!
digunakan :Untuk OS yang memiliki getopt yang disempurnakan yang mendukung opsi panjang (misalnya Linux), Anda dapat melakukan:
Untuk sisanya, Anda harus menggunakan opsi pendek:
Menambahkan bendera baru semudah menambahkan bendera baru
DEFINE_ call
.sumber
Menggunakan
getopts
dengan opsi / argumen pendek / panjangBekerja dengan semua kombinasi, misalnya:
Beberapa deklarasi untuk contoh ini
Bagaimana fungsi Penggunaan akan terlihat
getops
dengan bendera panjang / pendek serta argumen panjangKeluaran
Menggabungkan hal-hal di atas menjadi naskah yang kohesif
sumber
eval
pendekatan untuk argumen spasi pada opsi panjang dan merasa tidak dapat diandalkan dengan shell tertentu (meskipun saya berharap ini akan bekerja dengan bash, dalam hal ini Anda tidak perlu menggunakaneval
). Lihat jawaban saya untuk cara menerima argumen opsi panjang=
dan upaya saya yang dicatat untuk menggunakan ruang. Solusi saya tidak membuat panggilan eksternal sementara yang ini menggunakancut
beberapa kali.Cara lain...
sumber
$args
penugasan kembali? Ini bahkan bisa dilakukan tanpa bashism, tetapi kode ini akan kehilangan ruang dalam opsi dan argumen (saya pikir$delim
triknya tidak akan berhasil). Anda bisa menjalankannyaset
di dalamfor
loop jika cukup hati-hati untuk mengosongkannya hanya pada iterasi pertama. Ini adalah versi yang lebih aman tanpa bashism.Saya semacam dipecahkan dengan cara ini:
Apakah saya bodoh atau semacamnya?
getopt
dangetopts
sangat membingungkan.sumber
-ltr
atau-lt -r
juga-l -t -r
). Dan itu juga menyediakan beberapa penanganan kesalahan, dan cara mudah untuk memindahkan parameter yang dirawat begitu opsi perawatan selesai.Jika Anda tidak menginginkannya
getopt
ketergantungan, Anda dapat melakukan ini:Tentu saja, maka Anda tidak dapat menggunakan opsi gaya panjang dengan satu tanda hubung. Dan jika Anda ingin menambahkan versi singkat (mis. --Verbos bukan --verbose), maka Anda perlu menambahkannya secara manual.
Tetapi jika Anda mencari untuk mendapatkan
getopts
fungsionalitas bersama dengan opsi panjang, ini adalah cara sederhana untuk melakukannya.Saya juga menaruh cuplikan ini di intinya .
sumber
--)
sepertinya ada yangshift ;
hilang. Saat ini--
argumen tersebut akan tetap sebagai argumen non opsi pertama.--
opsi perlushift
di sana. Saya mengatakan ini lebih baik karena alternatifnya adalah versi tergantung platformgetopt
ataugetopts_long
atau Anda harus memaksa opsi pendek untuk digunakan hanya pada awal perintah (yaitu - Anda menggunakangetopts
kemudian memproses opsi lama setelah itu), sedangkan ini memberikan perintah apa pun dan kontrol penuh.Built-in
getopts
tidak dapat melakukan ini. Ada program getopt eksternal (1) yang dapat melakukan ini, tetapi Anda hanya mendapatkannya di Linux dari paket util-linux . Itu datang dengan contoh skrip getopt-parse.bash .Ada juga yang
getopts_long
ditulis sebagai fungsi shell.sumber
getopt
termasuk dalam versi FreeBSD 1.0 pada tahun 1993, dan telah menjadi bagian dari FreeBSD sejak saat itu. Dengan demikian, ini diadopsi dari FreeBSD 4.x untuk dimasukkan dalam proyek Darwin Apple. Pada OS X 10.6.8, halaman manual yang disertakan oleh Apple tetap merupakan duplikat halaman manual FreeBSD. Jadi ya, itu termasuk dalam OS X dan sekumpulan sistem operasi lain di samping Linux. -1 pada jawaban ini untuk informasi yang salah..
sumber
"${1:0:1}"
untuk argumen # 1, substring pada indeks 0, panjang 1. Ini tidak mengizinkan pencampuran opsi pendek dan panjang.Dalam
ksh93
,getopts
apakah mendukung nama panjang ...Atau begitulah tutorial yang saya temukan mengatakan. Cobalah dan lihatlah.
sumber
Saya hanya menulis skrip shell sekarang dan kemudian dan keluar dari latihan, sehingga umpan balik sangat dihargai.
Menggunakan strategi yang diusulkan oleh @Arvid Requate, kami menemukan beberapa kesalahan pengguna. Seorang pengguna yang lupa untuk memasukkan nilai secara tidak sengaja akan membuat nama opsi berikutnya diperlakukan sebagai nilai:
akan menyebabkan nilai "loglevel" dilihat sebagai "--toc = TRUE". Ini bisa dihindari.
Saya mengadaptasi beberapa ide tentang memeriksa kesalahan pengguna untuk CLI dari http://mwiki.wooledge.org/BashFAQ/035 diskusi parsing manual. Saya memasukkan kesalahan saat menangani argumen "-" dan "-".
Lalu saya mulai mengutak-atik sintaksis, jadi kesalahan apa pun di sini sepenuhnya salah saya, bukan penulis asli.
Pendekatan saya membantu pengguna yang lebih suka masuk lama dengan atau tanpa tanda sama dengan. Artinya, ia harus memiliki respons yang sama terhadap "--loglevel 9" dengan "--loglevel = 9". Dalam metode - / space, tidak mungkin untuk mengetahui dengan pasti apakah pengguna lupa argumen, sehingga beberapa tebakan diperlukan.
Jika Anda memulai ini, ada perbedaan yang menarik antara format "--opt = value" dan "--opt value". Dengan tanda sama dengan, argumen baris perintah dilihat sebagai "opt = value" dan pekerjaan untuk menangani itu adalah parsing string, untuk memisahkan pada "=". Sebaliknya, dengan "--opt value", nama argumennya adalah "opt" dan kami memiliki tantangan untuk mendapatkan nilai berikutnya yang disediakan di baris perintah. Di situlah @Arvid Requate menggunakan $ {! OPTIND}, referensi tidak langsung. Saya masih tidak mengerti itu, well, sama sekali, dan komentar di BashFAQ tampaknya memperingatkan terhadap gaya itu ( http://mywiki.wooledge.org/BashFAQ/006 ). BTW, saya tidak berpikir komentar poster sebelumnya tentang pentingnya OPTIND = $ (($ OPTIND + 1)) benar. Maksud saya mengatakan,
Dalam versi terbaru dari skrip ini, flag -v berarti cetakan VERBOSE.
Simpan dalam file yang disebut "cli-5.sh", buat dapat dieksekusi, dan semua ini akan berfungsi, atau gagal dengan cara yang diinginkan
Berikut adalah contoh keluaran dari pengecekan kesalahan pada intpu pengguna
Anda harus mempertimbangkan mengaktifkan -v, karena mencetak internal OPTIND dan OPTARG
sumber
OPTIND=$(( $OPTIND + 1 ))
: diperlukan setiap kali Anda 'melahap' parameter OPTIND (untuk contoh: ketika yang digunakan--toc value
: nilai dalam nomor parameter $ OPTIND. Setelah Anda mengambilnya untuk nilai toc, Anda harus memberi tahu getopts bahwa parameter berikutnya yang diurai bukan nilai, tetapi satu setelah itu (maka:.OPTIND=$(( $OPTIND + 1 ))
dan skrip Anda (serta skrip yang Anda rujuk) tidak ada, setelah selesai:shift $(( $OPTIND -1 ))
(saat getop keluar setelah parsing parameterrs 1 ke OPTIND-1, Anda perlu menggesernya begitu$@
sekarang menjadi parameter "non-opsi" yang tersisaMenemukan versi lain dari roda ...
Fungsi ini adalah (mudah-mudahan) POSIX-kompatibel pengganti shell bourne untuk GNU getopt. Ini mendukung opsi pendek / panjang yang dapat menerima argumen wajib / opsional / tidak, dan cara menentukan opsi hampir identik dengan GNU getopt, sehingga konversi sepele.
Tentu saja ini masih merupakan potongan kode yang cukup besar untuk dimasukkan ke dalam skrip, tetapi ini sekitar setengah baris dari fungsi shell getopt_long yang terkenal, dan mungkin lebih disukai dalam kasus di mana Anda hanya ingin mengganti penggunaan getopt GNU yang ada.
Ini adalah kode yang cukup baru, jadi YMMV (dan tentu saja tolong beri tahu saya jika ini sebenarnya tidak kompatibel dengan POSIX untuk alasan apa pun - portabilitas adalah niat sejak awal, tetapi saya tidak memiliki lingkungan pengujian POSIX yang berguna).
Kode dan contoh penggunaannya sebagai berikut:
Contoh penggunaan:
sumber
Jawaban yang diterima melakukan pekerjaan yang sangat baik untuk menunjukkan semua kekurangan bash built-in
getopts
. Jawabannya berakhir dengan:Dan meskipun saya setuju secara prinsip dengan pernyataan itu, saya merasa bahwa berapa kali kita semua menerapkan fitur ini dalam berbagai skrip membenarkan upaya untuk menciptakan solusi "standar", teruji dengan baik.
Karena itu, saya telah "memutakhirkan" bash yang dibangun
getopts
dengan menerapkangetopts_long
bash murni, tanpa ketergantungan eksternal. Penggunaan fungsi ini 100% kompatibel dengan built-ingetopts
.Dengan memasukkan
getopts_long
(yang di- host di GitHub ) dalam sebuah skrip, jawaban atas pertanyaan awal dapat diimplementasikan sesederhana:sumber
Saya belum memiliki cukup perwakilan untuk mengomentari atau memilih solusinya, tetapi jawaban sme bekerja sangat baik untuk saya. Satu-satunya masalah yang saya temui adalah bahwa argumen akhirnya dibungkus dengan tanda kutip tunggal (jadi saya harus menghapusnya).
Saya juga menambahkan beberapa contoh penggunaan dan BANTUAN teks. Saya akan menyertakan versi saya yang sedikit diperpanjang di sini:
sumber
Di sini Anda dapat menemukan beberapa pendekatan berbeda untuk penguraian opsi kompleks di bash: http://mywiki.wooledge.org/ComplexOptionParsing
Saya memang membuat yang berikut ini, dan saya pikir ini bagus, karena kode minimal dan opsi panjang dan pendek berfungsi. Opsi panjang juga dapat memiliki beberapa argumen dengan pendekatan ini.
sumber
Saya telah mengerjakan hal itu untuk waktu yang cukup lama ... dan membuat perpustakaan saya sendiri yang Anda perlu sumber dalam naskah utama Anda. Lihat libopt4shell dan cd2mpc untuk contohnya. Semoga ini bisa membantu!
sumber
Solusi yang ditingkatkan:
sumber
Mungkin lebih mudah menggunakan ksh, hanya untuk bagian getopts, jika perlu opsi baris perintah yang panjang, karena bisa lebih mudah dilakukan di sana.
sumber
Saya menginginkan sesuatu tanpa ketergantungan eksternal, dengan dukungan bash yang ketat (-u), dan saya membutuhkannya untuk bekerja pada versi bash yang lebih lama. Ini menangani berbagai jenis params:
Cukup masukkan yang berikut di bagian atas skrip Anda:
Dan gunakan seperti ini:
sumber
Agar tetap cross-platform yang kompatibel, dan menghindari ketergantungan pada executable eksternal, saya porting beberapa kode dari bahasa lain.
Saya merasa sangat mudah digunakan, berikut adalah contohnya:
BASH yang diperlukan sedikit lebih lama dari yang seharusnya, tetapi saya ingin menghindari ketergantungan pada array asosiatif BASH 4. Anda juga dapat mengunduh ini langsung dari http://nt4.com/bash/argparser.inc.sh
sumber
Jika semua opsi panjang Anda memiliki karakter pertama yang unik dan cocok, sebagai opsi pendek, maka misalnya
Sama dengan
Anda dapat menggunakan ini sebelum getopts untuk menulis ulang $ args:
Terima kasih atas mtvee untuk inspirasi ;-)
sumber
jika ini adalah bagaimana Anda ingin memanggil skrip
maka Anda dapat mengikuti cara paling sederhana untuk mencapainya dengan bantuan getopt dan --longtions
coba ini, semoga ini bermanfaat
sumber
getopts "bisa digunakan" untuk mem-parsing opsi-opsi panjang selama Anda tidak berharap mereka memiliki argumen ...
Begini caranya:
Jika Anda mencoba menggunakan OPTIND untuk mendapatkan parameter untuk opsi panjang, getopt akan memperlakukannya sebagai yang pertama tanpa parameter posisi opsional dan akan berhenti mem-parsing parameter lainnya. Dalam kasus seperti itu, Anda akan lebih baik menanganinya secara manual dengan pernyataan kasus sederhana.
Ini akan "selalu" berfungsi:
Meskipun tidak sefleksiet getopts dan Anda harus melakukan sendiri sebagian besar kesalahan pengecekan kode dalam kasus kasing ...
Tapi itu pilihan.
sumber
Builtin
getopts
hanya mengurai opsi pendek (kecuali dalam ksh93), tetapi Anda masih dapat menambahkan beberapa baris skrip untuk membuat getop menangani opsi panjang.Berikut adalah bagian dari kode yang ditemukan di http://www.uxora.com/unix/shell-script/22-handle-long-options-with-getopts
Ini tesnya:
Kalau tidak, di Korn Shell ksh93 baru-baru ini,
getopts
secara alami dapat mengurai opsi panjang dan bahkan menampilkan halaman manual. (Lihat http://www.uxora.com/unix/shell-script/20-getopts-with-man-page-and-long-options )sumber
Th built-in OS X (BSD) getopt tidak mendukung opsi panjang, tapi versi GNU tidak:
brew install gnu-getopt
. Kemudian, sesuatu yang mirip dengan:cp /usr/local/Cellar/gnu-getopt/1.1.6/bin/getopt /usr/local/bin/gnu-getopt
.sumber
EasyOptions menangani opsi pendek dan panjang:
sumber