Katakanlah, saya memiliki skrip yang dipanggil dengan baris ini:
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
atau yang ini:
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
Apa cara yang diterima parsing ini sehingga dalam setiap kasus (atau beberapa kombinasi dari dua) $v
, $f
dan $d
semua akan diatur true
dan $outFile
akan sama dengan /fizz/someOtherFile
?
zparseopts -D -E -M -- d=debug -debug=d
Dan memiliki keduanya-d
dan--debug
dalam$debug
arrayecho $+debug[1]
akan mengembalikan 0 atau 1 jika salah satu dari mereka digunakan. Ref: zsh.org/mla/users/2011/msg00350.htmlJawaban:
Metode # 1: Menggunakan bash tanpa getopt [s]
Dua cara umum untuk menyampaikan argumen pasangan kunci-nilai adalah:
Bash Space-Separated (eg,
--option argument
) (tanpa getopt [s])Pemakaian
demo-space-separated.sh -e conf -s /etc -l /usr/lib /etc/hosts
output dari copy-paste blok di atas:
Bash Equals-Separated (eg,
--option=argument
) (tanpa getopt [s])Pemakaian
demo-equals-separated.sh -e=conf -s=/etc -l=/usr/lib /etc/hosts
output dari copy-paste blok di atas:
Untuk lebih memahami
${i#*=}
pencarian "Penghapusan Substring" dalam panduan ini . Secara fungsional ini setara dengan`sed 's/[^=]*=//' <<< "$i"`
panggilan subproses yang tidak perlu atau`echo "$i" | sed 's/[^=]*=//'`
yang memanggil dua subproses yang tidak perlu.Metode # 2: Menggunakan bash dengan getopt [s]
dari: http://mywiki.wooledge.org/BashFAQ/035#getopts
batasan getopt (1) (
getopt
versi lama, relatif baru ):getopt
Versi yang lebih baru tidak memiliki batasan ini.Selain itu, shell POSIX (dan lainnya) menawarkan
getopts
yang tidak memiliki batasan ini. Saya telah memasukkangetopts
contoh sederhana .Pemakaian
demo-getopts.sh -vf /etc/hosts foo bar
output dari copy-paste blok di atas:
Keuntungannya
getopts
adalah:dash
.-vf filename
dalam cara Unix yang khas, secara otomatis.Kerugiannya
getopts
adalah ia hanya bisa menangani opsi pendek (-h
, tidak--help
) tanpa kode tambahan.Ada tutorial getopts yang menjelaskan apa arti semua sintaks dan variabel. Di bash, ada juga
help getopts
, yang mungkin informatif.sumber
getopt
yang mencakup semua fungsigetopts
dan beberapa.man getopt
pada Ubuntu 13,04 keluarangetopt - parse command options (enhanced)
seperti namanya, jadi saya kira versi yang disempurnakan ini adalah standar sekarang.getopt
bukan utilitas GNU, itu bagian dariutil-linux
.-gt 0
, hapusshift
setelah Andaesac
,shift
tambahkan semua dengan 1 dan tambahkan case ini:*) break;;
Anda dapat menangani argumen yang tidak opsional. Contoh: pastebin.com/6DJ57HTc–default
. Dalam contoh pertama, saya perhatikan bahwa jika–default
argumen terakhir, itu tidak diproses (dianggap sebagai non-opt), kecualiwhile [[ $# -gt 1 ]]
ditetapkan sebagaiwhile [[ $# -gt 0 ]]
Tidak ada jawaban yang menyebutkan getopt yang ditingkatkan . Dan jawaban yang terpilih adalah menyesatkan: ia mengabaikan
-vfd
opsi gaya pendek (diminta oleh OP) atau opsi setelah argumen posisi (juga diminta oleh OP); dan mengabaikan kesalahan parsing. Sebagai gantinya:getopt
dari util-linux atau sebelumnya GNU glibc . 1getopt_long()
fungsi C GNU glibc.getopt
tidak dapat melakukan ini)script.sh -o outFile file1 file2 -v
(getopts
tidak melakukan ini)=
opsi-gaya panjang:script.sh --outfile=fileOut --infile fileIn
(memungkinkan keduanya panjang jika parsing sendiri)-vfd
(pekerjaan nyata jika parsing sendiri)-oOutfile
atau-vfdoOutfile
getopt --test
→ mengembalikan nilai 4.getopt
atau built-in shellgetopts
adalah penggunaan terbatas.Panggilan berikut
semua kembali
dengan berikut ini
myscript
1 getopt yang ditingkatkan tersedia di sebagian besar "sistem-bash", termasuk Cygwin; pada OS X coba buat instal gnu-getopt atau
sudo port install getopt
2
exec()
konvensiPOSIXtidak memiliki cara yang dapat diandalkan untuk meneruskan NULL biner dalam argumen baris perintah; byte tersebut sebelum waktunya mengakhiri argumen3 versi pertama yang dirilis pada tahun 1997 atau sebelumnya (saya hanya melacaknya kembali ke 1997)
sumber
getopt
adalah jalan yang harus diambil.getopt
adalah bahwa hal itu tidak dapat digunakan dengan mudah dalam skrip pembungkus di mana orang mungkin memiliki beberapa opsi khusus untuk skrip pembungkus, dan kemudian meneruskan opsi skrip non-pembungkus ke executable yang dibungkus, utuh. Katakanlah saya memilikigrep
pembungkus yang dipanggilmygrep
dan saya memiliki opsi--foo
khusus untukmygrep
, maka saya tidak dapat melakukannyamygrep --foo -A 2
, dan-A 2
meneruskannya secara otomatis kegrep
; Saya perlu melakukannyamygrep --foo -- -A 2
. Inilah implementasi saya di atas solusi Anda.man bash
Cara yang lebih ringkas
script.sh
Pemakaian:
sumber
while [[ "$#" > 1 ]]
jika saya ingin mendukung mengakhiri garis dengan bendera boolean./script.sh --debug dev --uglify fast --verbose
. Contoh: gist.github.com/hfossli/4368aa5a577742c3c9f9266ed214aa58./script.sh -d dev -d prod
akan menghasilkandeploy == 'prod'
. Saya tetap menggunakannya: P :): +1:./script.sh -d
tidak akan menghasilkan kesalahan tetapi hanya disetel$deploy
ke string kosong.dari: digitalpeer.com dengan sedikit modifikasi
Pemakaian
myscript.sh -p=my_prefix -s=dirname -l=libname
Untuk lebih memahami
${i#*=}
pencarian "Penghapusan Substring" dalam panduan ini . Secara fungsional ini setara dengan`sed 's/[^=]*=//' <<< "$i"`
panggilan subproses yang tidak perlu atau`echo "$i" | sed 's/[^=]*=//'`
yang memanggil dua subproses yang tidak perlu.sumber
mount -t tempfs ...
. Seseorang mungkin dapat memperbaiki ini melalui sesuatu sepertiwhile [ $# -ge 1 ]; do param=$1; shift; case $param in; -p) prefix=$1; shift;;
dll-vfd
kombinasi opsi pendek gaya.getopt()
Sayagetopts()
adalah pilihan yang baik. Dicuri dari sini :sumber
$*
rusak penggunaangetopt
. (Ini menyembunyikan argumen dengan spasi.) Lihat jawaban saya untuk penggunaan yang tepat.Dengan risiko menambahkan contoh lain untuk diabaikan, inilah skema saya.
-n arg
dan--name=arg
Semoga bermanfaat bagi seseorang.
sumber
*) die "unrecognized argument: $1"
atau mengumpulkan args menjadi variabel*) args+="$1"; shift 1;;
.shift 2
, mengeluarkanshift
dua kali alih-alihshift 2
. Menyarankan hasil edit.Saya terlambat sekitar 4 tahun untuk pertanyaan ini, tetapi ingin memberi kembali. Saya menggunakan jawaban sebelumnya sebagai titik awal untuk merapikan parameter parsing adhoc lama saya. Saya kemudian refactored keluar kode templat berikut. Ia menangani params panjang dan pendek, menggunakan argumen = atau spasi terpisah, serta beberapa params pendek dikelompokkan bersama. Akhirnya ia memasukkan kembali argumen non-param kembali ke variabel $ 1, $ 2 .. Semoga bermanfaat.
sumber
-c1
. Dan penggunaan=
untuk memisahkan opsi pendek dari argumen mereka tidak biasa ...Saya telah menemukan masalah untuk menulis parsing portabel dalam skrip yang sangat membuat frustasi sehingga saya telah menulis Argbash - generator kode FOSS yang dapat menghasilkan kode parsing argumen untuk skrip Anda plus memiliki beberapa fitur yang bagus:
https://argbash.io
sumber
Jawaban saya sebagian besar didasarkan pada jawaban oleh Bruno Bronosky , tapi saya semacam menumbuk dua implementasi bash murni menjadi satu yang saya gunakan cukup sering.
Ini memungkinkan Anda untuk memiliki kedua opsi / nilai yang dipisahkan dengan ruang, serta nilai yang didefinisikan sama.
Jadi Anda dapat menjalankan skrip Anda menggunakan:
sebaik:
dan keduanya harus memiliki hasil akhir yang sama.
PROS:
Memungkinkan untuk -arg = nilai dan nilai -arg
Bekerja dengan nama arg apa pun yang dapat Anda gunakan di bash
Bash murni. Tidak perlu belajar / menggunakan getopt atau getopt
CONS:
Tidak dapat menggabungkan args
Ini adalah satu-satunya pro / kontra yang bisa saya pikirkan dari atas kepala saya
sumber
Saya pikir ini cukup sederhana untuk digunakan:
Contoh doa:
sumber
-a=1
gaya argc. Saya lebih suka mengutamakan opsi-opsi utama dan kemudian yang khusus dengan spasi tunggal-o option
. Saya sedang mencari cara paling sederhana-vs-lebih baik untuk membaca argvs../myscript -v -d fail -o /fizz/someOtherFile -f ./foo/bar/someFile
dengan skrip Anda sendiri. -d opsi tidak diset sebagai d:Memperluas jawaban yang sangat baik oleh @guneysus, berikut ini adalah tweak yang memungkinkan pengguna menggunakan sintaksis mana pun yang mereka sukai, misalnya
vs.
Artinya persamaan bisa diganti dengan spasi putih.
"Interpretasi kabur" ini mungkin tidak sesuai dengan keinginan Anda, tetapi jika Anda membuat skrip yang dapat dipertukarkan dengan utilitas lain (seperti halnya dengan milik saya, yang harus bekerja dengan ffmpeg), fleksibilitasnya berguna.
sumber
Contoh ini menunjukkan cara menggunakan
getopt
daneval
danHEREDOC
danshift
menangani parameter pendek dan panjang dengan dan tanpa nilai yang diperlukan berikut. Juga pernyataan switch / casenya ringkas dan mudah diikuti.Baris paling penting dari skrip di atas adalah ini:
Singkat, to the point, dapat dibaca, dan menangani hampir semua hal (IMHO).
Semoga itu bisa membantu seseorang.
sumber
Saya memberi Anda Fungsi
parse_params
yang akan mem-parsing params dari baris perintah.--all
sama-all
dengan samaall=all
)Script di bawah ini adalah demonstrasi kerja copy-paste. Lihat
show_use
fungsi untuk memahami cara menggunakanparse_params
.Keterbatasan:
-d 1
)--any-param
dan-anyparam
setaraeval $(parse_params "$@")
harus digunakan di dalam fungsi bash (tidak akan berfungsi dalam lingkup global)sumber
show_use "$@"
EasyOptions tidak memerlukan penguraian:
sumber
getopts berfungsi dengan baik jika # 1 Anda menginstalnya dan # 2 Anda bermaksud menjalankannya pada platform yang sama. OSX dan Linux (misalnya) berperilaku berbeda dalam hal ini.
Berikut adalah solusi (non getopts) yang mendukung flag sama dengan, tidak sama, dan boolean. Misalnya Anda dapat menjalankan skrip Anda dengan cara ini:
sumber
Inilah yang saya lakukan dalam suatu fungsi untuk menghindari kerusakan menjalankan getop pada saat yang sama di suatu tempat yang lebih tinggi di stack:
sumber
Memperluas jawaban @ bruno-bronosky, saya menambahkan "preprocessor" untuk menangani beberapa format umum:
--longopt=val
menjadi--longopt val
-xyz
menjadi-x -y -z
--
untuk menunjukkan akhir benderasumber
Ada beberapa cara untuk mengurai argumen cmdline (mis. GNU getopt (bukan portable) vs BSD (OSX) getopt vs getopts) - semuanya bermasalah. Solusi ini
=
pemisah-vxf
Contoh: Salah satu dari
sumber
Saya ingin menawarkan parsing opsi versi saya, yang memungkinkan untuk yang berikut:
Juga memungkinkan untuk ini (bisa tidak diinginkan):
Anda harus memutuskan sebelum menggunakan apakah = akan digunakan pada opsi atau tidak. Ini untuk menjaga kode tetap bersih (ish).
sumber
Solusi yang mempertahankan argumen tidak tertangani. Demo Termasuk.
Ini solusinya. Ini SANGAT fleksibel dan tidak seperti yang lain, seharusnya tidak memerlukan paket eksternal dan menangani argumen sisa dengan bersih.
Penggunaannya adalah:
./myscript -flag flagvariable -otherflag flagvar2
Yang harus Anda lakukan adalah mengedit baris tanda valid. Ini menambahkan tanda hubung dan mencari semua argumen. Itu kemudian mendefinisikan argumen berikutnya sebagai nama bendera misalnya
Kode utama (versi pendek, verbose dengan contoh lebih jauh ke bawah, juga versi dengan kesalahan):
Versi verbose dengan demo gema bawaan:
Yang terakhir, kesalahan yang satu ini keluar jika -argumen yang tidak valid dilewatkan.
Pro: Apa yang dilakukannya, itu menangani dengan sangat baik. Ini mempertahankan argumen yang tidak digunakan yang banyak dari solusi lain di sini tidak. Hal ini juga memungkinkan variabel dipanggil tanpa harus didefinisikan dengan tangan dalam skrip. Ini juga memungkinkan pra-populasi variabel jika tidak ada argumen yang sesuai diberikan. (Lihat contoh verbose).
Cons: Tidak dapat menguraikan string arg kompleks tunggal misalnya -xcvf akan diproses sebagai argumen tunggal. Anda dapat dengan mudah menulis kode tambahan ke tambang yang menambahkan fungsi ini.
sumber
Saya ingin mengirimkan proyek saya: https://github.com/flyingangel/argparser
Sederhana seperti itu. Lingkungan akan diisi dengan variabel dengan nama yang sama dengan argumen
sumber
Catat itu
getopt(1)
itu adalah kesalahan hidup singkat dari AT&T.getopt dibuat pada tahun 1984 tetapi sudah dimakamkan pada tahun 1986 karena itu tidak benar-benar dapat digunakan.
Sebuah bukti untuk fakta yang
getopt
sangat ketinggalan jaman adalah bahwagetopt(1)
halaman manual masih menyebutkan"$*"
bukannya"$@"
, yang ditambahkan ke Bourne Shell pada tahun 1986 bersama dengangetopts(1)
shell builtin untuk menangani argumen dengan ruang di dalamnya.BTW: jika Anda tertarik untuk menguraikan opsi panjang dalam skrip shell, mungkin menarik untuk mengetahui bahwa
getopt(3)
implementasi dari libc (Solaris) danksh93
keduanya menambahkan implementasi opsi panjang yang seragam yang mendukung opsi panjang sebagai alias untuk opsi pendek. Ini menyebabkanksh93
danBourne Shell
untuk mengimplementasikan antarmuka yang seragam untuk opsi panjang viagetopts
.Contoh untuk opsi panjang yang diambil dari halaman manual Bourne Shell:
getopts "f:(file)(input-file)o:(output-file)" OPTX "$@"
menunjukkan berapa lama alias opsi dapat digunakan di Bourne Shell dan ksh93.
Lihat halaman manual dari Bourne Shell terbaru:
http://schillix.sourceforge.net/man/man1/bosh.1.html
dan halaman manual untuk getopt (3) dari OpenSolaris:
http://schillix.sourceforge.net/man/man3c/getopt.3c.html
dan terakhir, halaman manual getopt (1) untuk memverifikasi $ * yang sudah usang:
http://schillix.sourceforge.net/man/man1/getopt.1.html
sumber
Saya telah menulis bash helper untuk menulis alat bash yang bagus
rumah proyek: https://gitlab.mbedsys.org/mbedsys/bashopts
contoh:
akan memberi bantuan:
Nikmati :)
sumber
Inilah pendekatan saya - menggunakan regexp.
-qwerty
-q -w -e
--qwerty
=
untuk menyediakan atribut, tetapi atribut cocok sampai bertemu dengan tanda hubung + spasi "pembatas", jadi dalam--q=qwe ty
qwe ty
adalah satu atribut-o a -op attr ibute --option=att ribu te --op-tion attribute --option att-ribute
validnaskah:
sumber
Asumsikan kita membuat skrip shell bernama
test_args.sh
sebagai followSetelah kami menjalankan perintah berikut:
Outputnya adalah:
sumber
Gunakan modul "argumen" dari bash-modules
Contoh:
sumber
Menggabungkan argumen berbasis posisi dan bendera
--param = arg (sama dengan dibatasi)
Mencampur bendera dengan bebas di antara argumen posisi:
dapat dicapai dengan pendekatan yang cukup ringkas:
--param arg (dibatasi ruang)
Biasanya lebih jelas untuk tidak memadukan
--flag=value
dan--flag value
gaya.Ini agak tidak pasti untuk dibaca, tetapi masih valid
Sumber
sumber
Berikut adalah getopts yang mencapai parsing dengan kode minimal dan memungkinkan Anda untuk menentukan apa yang ingin Anda ekstrak dalam satu kasus menggunakan eval with substring.
Pada dasarnya
eval "local key='val'"
Deklarasikan variabel sebagai lokal bukan global karena sebagian besar jawaban di sini.
Disebut sebagai:
$ {K: 3} pada dasarnya adalah sebuah substring untuk menghapus yang pertama
---
dari kunci.sumber
Ini juga mungkin berguna untuk diketahui, Anda dapat menetapkan nilai dan jika seseorang memberikan input, ganti default dengan nilai itu.
myscript.sh -f ./serverlist.txt atau hanya ./myscript.sh (dan dibutuhkan default)
sumber
Solusi lain tanpa getopt [POS], POSIX, gaya Unix lama
Mirip dengan solusi yang diposting Bruno Bronosky ini di sini adalah satu tanpa penggunaan
getopt(s)
.Fitur pembeda utama dari solusi saya adalah memungkinkan untuk memiliki opsi yang disatukan bersama-
tar -xzf foo.tar.gz
sama sama dengantar -x -z -f foo.tar.gz
. Dan seperti ditar
,ps
dll. Tanda hubung utama adalah opsional untuk blok opsi pendek (tetapi ini dapat diubah dengan mudah). Opsi panjang juga didukung (tetapi ketika sebuah blok dimulai dengan satu maka dua tanda hubung utama diperlukan).Kode dengan opsi contoh
Untuk contoh penggunaan, silakan lihat contoh lebih lanjut di bawah ini.
Posisi opsi dengan argumen
Untuk apa nilainya di sana, opsi dengan argumen tidak menjadi yang terakhir (hanya opsi panjang yang diperlukan). Jadi sementara misalnya dalam
tar
(setidaknya dalam beberapa implementasi)f
opsi harus yang terakhir karena nama file mengikuti (tar xzf bar.tar.gz
berfungsi tetapitar xfz bar.tar.gz
tidak) ini tidak terjadi di sini (lihat contoh selanjutnya).Opsi berganda dengan argumen
Sebagai bonus lain, parameter opsi dikonsumsi dalam urutan opsi oleh parameter dengan opsi yang diperlukan. Lihat saja hasil skrip saya di sini dengan baris perintah
abc X Y Z
(atau-abc X Y Z
):Opsi panjang juga digabungkan
Anda juga dapat memiliki opsi panjang di blok opsi mengingat bahwa mereka muncul terakhir di blok. Jadi baris perintah berikut semuanya setara (termasuk urutan di mana opsi dan argumennya sedang diproses):
-cba Z Y X
cba Z Y X
-cb-aaa-0-args Z Y X
-c-bbb-1-args Z Y X -a
--ccc-2-args Z Y -ba X
c Z Y b X a
-c Z Y -b X -a
--ccc-2-args Z Y --bbb-1-args X --aaa-0-args
Semua ini mengarah ke:
Tidak dalam solusi ini
Argumen opsional
Opsi dengan argumen opsional harus dimungkinkan dengan sedikit kerja, misalnya dengan melihat ke depan apakah ada blok tanpa tanda hubung; pengguna kemudian harus meletakkan tanda hubung di depan setiap blok mengikuti blok dengan parameter yang memiliki parameter opsional. Mungkin ini terlalu rumit untuk berkomunikasi dengan pengguna jadi lebih baik hanya memerlukan tanda hubung terkemuka sama sekali dalam kasus ini.
Banyak hal menjadi lebih rumit dengan beberapa parameter yang mungkin. Saya akan menyarankan untuk tidak membuat pilihan yang mencoba menjadi pintar dengan menentukan apakah suatu argumen mungkin untuk itu atau tidak (misalnya dengan opsi hanya mengambil angka sebagai argumen opsional) karena ini mungkin pecah di masa depan.
Saya pribadi menyukai opsi tambahan, bukan argumen opsional.
Argumen opsi diperkenalkan dengan tanda sama dengan
Sama seperti dengan argumen opsional, saya bukan penggemar ini (BTW, apakah ada utas untuk membahas pro / kontra dari berbagai gaya parameter?) Tetapi jika Anda menginginkan ini, Anda mungkin bisa menerapkannya sendiri seperti yang dilakukan di http: // mywiki.wooledge.org/BashFAQ/035#Manual_loop dengan
--long-with-arg=?*
pernyataan kasus dan kemudian membuang tanda sama dengan (ini adalah BTW situs yang mengatakan bahwa membuat penggabungan parameter dimungkinkan dengan beberapa upaya tetapi "meninggalkannya sebagai latihan untuk pembaca "Yang membuat saya menerima kata-kata mereka tetapi saya mulai dari awal).Catatan lain
Sesuai dengan POSIX, berfungsi bahkan pada pengaturan Busybox kuno yang harus saya tangani (misalnya
cut
,head
dangetopts
hilang).sumber