Saya ingat pernah melihat di suatu tempat bash
skrip menggunakan case
dan shift
berjalan melalui daftar parameter posisi, mengurai flag dan opsi dengan argumen ketika bertemu mereka, dan menghapusnya setelah parsing hanya meninggalkan argumen kosong, yang kemudian diproses oleh sisa dari naskah.
Misalnya, dalam mem-parsing baris perintah cp -R file1 -t /mybackup file2 -f
, pertama-tama ia akan berjalan melalui parameter, mengenali bahwa pengguna telah meminta untuk turun ke direktori dengan -R
, menentukan target dengan -t /mybackup
dan untuk memaksa menyalin -f
, dan menghapus yang dari daftar parameter, meninggalkan program untuk diproses file1 file2
sebagai argumen yang tersisa.
Tapi sepertinya saya tidak bisa mengingat / mencari tahu naskah apa pun yang saya lihat kapan saja. Saya hanya ingin bisa melakukan itu. Saya telah googling di berbagai situs dan menambahkan daftar halaman yang relevan yang saya periksa.
Sebuah pertanyaan di situs web ini secara khusus bertanya tentang "opsi tidak tergantung pesanan" tetapi baik jawaban tunggal maupun jawaban pertanyaan yang ditiru tidak mempertimbangkan kasus-kasus seperti di atas di mana opsi dicampur dengan argumen normal, yang saya anggap sebagai alasan bagi orang tersebut untuk secara spesifik menyebutkan opsi pesanan-independen .
Karena bash
built-in getopts
tampaknya berhenti pada argumen non-opsi pertama, sepertinya tidak cukup sebagai solusi. Inilah sebabnya mengapa halaman Wooledge BashFAQ (lihat di bawah) menjelaskan cara mengatur ulang argumen. Tetapi saya ingin menghindari membuat banyak array jika daftar argumennya cukup panjang.
Karena shift
tidak mendukung memunculkan argumen individual di bagian tengah daftar parameter, saya tidak yakin apa cara langsung untuk mengimplementasikan apa yang saya minta.
Saya ingin mendengar jika ada yang punya solusi untuk menghapus argumen dari tengah daftar parameter tanpa membuat array baru.
Halaman yang sudah saya lihat:
- http://mywiki.wooledge.org/ComplexOptionParsing#Rearranging_arguments
- http://mywiki.wooledge.org/BashFAQ/035
- Menggunakan getop dalam skrip bash shell untuk mendapatkan opsi baris perintah yang panjang dan pendek
- http://wiki.bash-hackers.org/scripting/posparams
- http://wiki.bash-hackers.org/howto/getopts_tutorial
- bash argumen case untuk args dalam $ @
- Apa cara kanonik untuk menerapkan opsi independen pesanan dalam skrip bash?
- Bagaimana cara menangani sakelar dalam skrip shell?
Jawaban:
POSIXly, penguraian untuk opsi harus berhenti pada
--
atau pada argumen non-opsi (atau non-opsi-argumen) pertama yang mana yang lebih dulu. Jadi masukyang ini di
file1
, jadicp
harus rekursif menyalin semuafile1
,-t
,/mybackup
danfile2
ke dalam-f
direktori.getopt(3)
Namun, GNU (yangcp
digunakan GNU untuk menguraikan opsi (dan di sini Anda menggunakan GNUcp
karena Anda menggunakan-t
opsi spesifik GNU )), kecuali$POSIXLY_CORRECT
variabel lingkungan diatur, menerima opsi setelah argumen. Jadi itu sebenarnya setara dengan parsing gaya opsi POSIX:The
getopts
shell built-in, bahkan di GNU shell (bash
) hanya menangani gaya POSIX. Itu juga tidak mendukung opsi panjang atau opsi dengan argumen opsional.Jika Anda ingin menguraikan opsi dengan cara yang sama seperti GNU
cp
, Anda harus menggunakangetopt(3)
API GNU . Untuk itu, jika di Linux, Anda dapat menggunakangetopt
utilitas yang disempurnakan dariutil-linux
( versi yang disempurnakan darigetopt
perintah tersebut juga telah porting ke beberapa Unix lain seperti FreeBSD ).Itu
getopt
akan mengatur ulang opsi dengan cara kanonik yang memungkinkan Anda untuk menguraikannya hanya dengan satuwhile/case
lingkaran.Anda biasanya menggunakannya sebagai:
Perhatikan juga bahwa itu
getopt
akan mem-parsing opsi dengan cara yang sama seperti GNUcp
. Secara khusus, ini mendukung opsi panjang (dan memasukkannya disingkat) dan menghargai$POSIXLY_CORRECT
variabel lingkungan (yang ketika disetel menonaktifkan dukungan untuk opsi setelah argumen) dengan cara yang sama seperti GNUcp
.Perhatikan bahwa menggunakan gdb dan mencetak argumen yang
getopt_long()
menerima dapat membantu membangun parameter kegetopt(1)
:Maka Anda dapat menggunakan
getopt
sebagai:Ingatlah bahwa
cp
daftar opsi yang didukung GNU dapat berubah dari satu versi ke versi berikutnya dan yanggetopt
tidak akan dapat memeriksa apakah Anda memberikan nilai legal ke--sparse
opsi misalnya.sumber
while [ "$#" -gt 0 ]
iowhile (($#))
? Apakah hanya untuk menghindari bashism?(($#))
lebih kshism .Jadi setiap kali
getopts
memproses argumen, ia tidak berharap itu menetapkan variabel shell$OPTIND
ke nomor berikutnya dalam daftar argumen yang harus diproses dan mengembalikan selain 0. Jika$OPTIND
diatur ke nilai 1,getopts
ditentukan POSIX untuk menerima daftar argumen baru. Jadi ini hanya menontongetopts
kembali, menyimpan kenaikan counter plus$OPTIND
untuk setiap pengembalian yang gagal, menggeser argumen yang gagal, dan me-reset$OPTIND
setiap percobaan yang gagal. Anda dapat menggunakannya sepertiopts "$@"
- meskipun Anda ingin menyesuaikancase
loop atau menyimpannya ke dalam variabel dan mengubah bagian itu menjadieval $case
.Saat menjalankannya disetel
$args
ke setiap argumen yanggetopts
tidak menangani ... jadi ...KELUARAN
Ini bekerja di
bash
,dash
,zsh
,ksh93
,mksh
... baik, saya berhenti berusaha pada saat itu. Di setiap shell juga punya$[Rtf]flag
dan$targ
. Intinya adalah bahwa semua angka untuk argumen yanggetopts
tidak ingin diproses tetap ada.Mengubah gaya opsi juga tidak membuat perbedaan. Itu bekerja seperti
-Rf -t/mybackup
atau-R -f -t /mybackup
. Itu bekerja di tengah daftar, di akhir daftar, atau di kepala daftar ...Tetap saja, cara terbaik adalah dengan menempelkan
--
opsi untuk akhir pada daftar arg Anda dan kemudian lakukanshift "$(($OPTIND-1))"
di akhirgetopts
proses pemrosesan. Dengan begitu Anda menghapus semua parameter yang diproses dan menjaga ujung daftar argumen.Satu hal yang saya suka lakukan adalah menerjemahkan opsi panjang menjadi pendek - dan saya melakukannya dengan cara yang sangat mirip karena itulah jawaban ini datang dengan mudah - sebelum saya menjalankan
getopts
.sumber
cp -t --file foo
ataucp -- --file foo
) dan tidak akan mengatasi opsi yang dimasukkan disingkat (--fi
...), atau dengan--target=/dest
sintaks.getopts
benda itu dengan fungsi yang lebih sederhana.opts()
ada kaitannya dengan jawaban Anda sendiri sebagaiopts()
bekerja dalam satu loop - menyentuh setiap argumen tapi sekali - dan melakukannya dengan andal ( sedekat yang saya tahu) , mudah dibawa, dan tanpa subkulit tunggal.-R
,-t /mybackup
,-f
). Saya akan menyimpan suara saya untuk saat ini karena masih dikaburkan, Anda menggunakan yang$a
belum diinisialisasi, danargs= opts...
kemungkinanargs
tidak akan disetel (atau disetel seperti sebelumnya) setelahopts
kembali dalam banyak cangkang (termasuk bash).bash
- Saya benci itu. Menurut pendapat saya, jika fungsinya adalah fungsi shell saat ini yang harus dipertahankan. Saya menangani hal-hal ini - karena fungsi saat ini, dengan lebih banyak tes, dapat dibuat untuk menangani semua kasus, dan bahkan untuk menandai argumen dengan opsi sebelumnya, tetapi saya tidak setuju bahwa itu dikaburkan . Seperti yang tertulis, ini adalah cara paling sederhana dan paling langsung untuk menyelesaikan tugasnya yang dapat saya pikirkan.test
makashift
tidak masuk akal ketika dalam setiapshift
kasus gagal Anda harusreturn
. Ini tidak dimaksudkan untuk melakukan sebaliknya.