Saya bingung bagaimana memasukkan argumen / bendera opsional saat menulis skrip bash untuk program berikut:
Program ini membutuhkan dua argumen:
run_program --flag1 <value> --flag2 <value>
Namun, ada beberapa flag opsional:
run_program --flag1 <value> --flag2 <value> --optflag1 <value> --optflag2 <value> --optflag3 <value> --optflag4 <value> --optflag5 <value>
Saya ingin menjalankan skrip bash sehingga dibutuhkan argumen pengguna. Jika pengguna hanya memasukkan dua argumen secara berurutan, maka itu akan menjadi:
#!/bin/sh
run_program --flag1 $1 --flag2 $2
Tetapi bagaimana jika ada argumen opsional yang disertakan? Saya akan berpikir itu akan terjadi
if [ --optflag1 "$3" ]; then
run_program --flag1 $1 --flag2 $2 --optflag1 $3
fi
Tetapi bagaimana jika $ 4 diberikan tetapi bukan $ 3?
shell-script
arguments
ShanZhengYang
sumber
sumber
getopts
adalah apa yang kamu inginkan. Tanpa itu, Anda bisa menggunakan loop dengan pernyataan switch untuk mendeteksi setiap flag, opsional atau tidak.getopts
, saya perlu menentukan setiap kombinasi argumen? 3 & 4, 3 & 5, 3 & 4 & 5, dll?getopts
. Katakanlah saya memaksa pengguna untuk menjalankan skrip dengan semua argumen:run_program.sh VAL VAL FALSE FALSE FALSE FALSE FALSE
yang menjalankan program sebagaiprogram --flag1 VAL --flag2 VAL
. Jika Anda berlarirun_program.sh VAL VAL FALSE 10 FALSE FALSE FALSE
, program akan berjalan sebagaiprogram --flag1 VAL --flag2 VAL --optflag2 10
. Bagaimana Anda bisa mendapatkan perilaku seperti itugetopts
?Jawaban:
Artikel ini menunjukkan dua cara berbeda -
shift
dangetopts
(dan membahas kelebihan dan kekurangan dari kedua pendekatan).Dengan
shift
melihat skrip Anda$1
, tentukan tindakan apa yang harus diambil, lalu jalankanshift
, pindah$2
ke$1
,$3
ke$2
, dll.Sebagai contoh:
Dengan
getopts
Anda menentukan opsi (pendek) dalamwhile
ekspresi:Jelas, ini hanya potongan kode, dan saya telah meninggalkan validasi - memeriksa bahwa args wajib flag1 dan flag2 diatur, dll.
Pendekatan yang Anda gunakan sampai batas tertentu adalah masalah selera - seberapa portabel Anda ingin skrip Anda, apakah Anda dapat hidup dengan opsi pendek (POSIX) saja atau apakah Anda ingin opsi panjang (GNU), dll.
sumber
while (( $# ))
alih - alihwhile :;
dan sering berhenti dengan kesalahan dalam*
kasus iniset -o nounset
solusi pertama akan kesalahan jika tidak ada parameter yang diberikan. Perbaiki:case ${1:-} in
gunakan sebuah array.
ini akan menangani argumen dengan spasi di dalamnya dengan benar.
[sunting] Saya menggunakan sintaks yang kurang lebih sama
args=( "${args[@]}" --optflag1 "$3" )
tetapi G-Man menyarankan cara yang lebih baik.sumber
args+=( --optflag1 "$3" )
. Anda mungkin ingin melihat jawaban saya untuk karya referensi kami, Implikasi keamanan gagal mengutip variabel dalam bash / POSIX shells , di mana saya membahas teknik ini (membangun baris perintah dalam array dengan menambahkan argumen opsional secara kondisional).[@]
saya memiliki alat yang cukup untuk menyelesaikan masalah saya.Dalam skrip shell, argumen adalah "$ 1", "$ 2", "$ 3", dll. Jumlah argumen adalah $ #.
Jika skrip Anda tidak mengenali opsi, Anda dapat mengabaikan deteksi opsi dan memperlakukan semua argumen sebagai operan.
Untuk mengenali opsi-opsi gunakan getop builtin
sumber
Jika opsi input Anda bersifat posisional (Anda tahu di mana mereka berada), dan tidak ditentukan dengan tanda, maka yang Anda inginkan hanyalah membangun baris perintah. Persiapkan argumen perintah untuk semuanya:
Jika parameter tidak ditentukan, maka string yang sesuai kosong dan berkembang menjadi nol. Perhatikan bahwa di baris terakhir, tidak ada tanda kutip. Itu karena Anda ingin shell untuk membagi parameter menjadi kata-kata (untuk memberikan
--flag1
dan$1
sebagai argumen terpisah untuk program Anda). Tentu saja, ini akan salah jika parameter asli Anda berisi spasi. Jika Anda yang menjalankan ini, maka Anda dapat meninggalkannya, tetapi jika itu adalah skrip umum, ia dapat memiliki perilaku yang tidak terduga jika pengguna memasukkan sesuatu dengan spasi. Untuk mengatasinya, Anda harus membuat kode sedikit lebih buruk.The
x
awalan di[]
uji ada dalam kasus$3
atau$4
kosong. Dalam hal ini, bash akan berkembang[ FALSE != $3 ]
menjadi[ FALSE != ]
kesalahan sintaks, jadi ada karakter arbitrer yang ada untuk menjaga hal ini. Ini adalah cara yang sangat umum, Anda akan melihatnya di banyak skrip.Saya atur
OPTFLAG1
dan sisanya""
pada awalnya hanya untuk memastikan (kalau-kalau mereka ditetapkan untuk sesuatu sebelumnya), tetapi jika mereka tidak benar-benar dideklarasikan di lingkungan, maka Anda tidak benar-benar perlu melakukan itu.Beberapa komentar tambahan:
runprogram
: dengan flags. Itulah yangJohn N
sedang dibicarakan. Di situlahgetopts
menjadi berguna.-
) untuk memberi sinyal nilai kosong, atau hanya meneruskan string kosong, seperti""
, jika itu bukan nilai parameter yang valid. String kosong juga membuat tes lebih pendek, cukup gunakanif [ -n "$3" ]
.""
untuk parameter kosong, seperti yang disarankan di atas, Anda dapat melewatkan semua sisa trailing.Metode ini cukup banyak cara opsi dilewatkan ke kompiler di Makefiles.
Dan lagi - jika input mungkin mengandung spasi, itu menjadi jelek.
sumber