Saya menulis skrip yang sangat sederhana yang memanggil skrip lain, dan saya perlu menyebarkan parameter dari skrip saya saat ini ke skrip yang saya jalankan.
Misalnya, nama skrip saya adalah foo.sh
dan panggilanbar.sh
foo.sh:
bar $1 $2 $3 $4
Bagaimana saya bisa melakukan ini tanpa secara eksplisit menentukan setiap parameter?
bash
command-line-arguments
Fragsworth
sumber
sumber
Jawaban:
Gunakan
"$@"
alih-alih polos$@
jika Anda benar-benar ingin agar parameter Anda lulus sama.Mengamati:
sumber
'arg with spaces'
tiga contoh juga. Saya terkejut dengan hasilnya; semoga Anda bisa menjelaskannya../foo.sh "arg with spaces"
dan./foo.sh 'arg with spaces'
100% identik, jadi saya tidak melihat bagaimana saran untuk menambahkannya ke contoh yang diberikan akan membantu.Untuk bash dan cangkang mirip Bourne lainnya:
sumber
$argv:q
akan bekerja di beberapa varian csh.exec java com.myserver.Program "$@"
Hal ini menyebabkan bash untuk mengeksekusi ke java, daripada menunggu sampai selesai. Jadi, Anda menggunakan satu slot proses kurang. Juga, jika proses induk (yang menjalankan skrip Anda) menontonnya melalui pid, dan mengharapkannya menjadi proses 'java', beberapa hal yang tidak biasa dapat rusak jika Anda tidak melakukan exec; exec menyebabkan java untuk mewarisi pid yang sama.args=("$@")
dan kembangkan setiap elemen sebagai "kata" shell yang terpisah ( mirip dengan"$@"
)"${args[@]}"
."$@"
, seperti apakah akan gagal jika Anda telah lolos spasi dalam argumen, atau karakter nol, atau karakter khusus lainnya?Gunakan
"$@"
(berfungsi untuk semua kompatibilitas POSIX ).Dari Bash dengan contoh .
sumber
$*
. Saya percaya ada perkembangan sejarah di sini;$*
tidak berfungsi seperti yang dirancang, jadi$@
diciptakan untuk menggantikannya; tetapi aturan kutip menjadi seperti apa adanya, tanda kutip ganda masih diperlukan (atau akan kembali ke$*
semantik yang rusak ).echo "$@"
sebagai./script.sh a "b c" d
maka Anda hanya mendapatkana b c d
bukana "b c" d
, yang sangat jauh berbeda.echo
menerima tiga argumen:"a" "b c" "d"
(kemudian shell bergabung bersama-sama sebagai bagian dari ekspansi string-nya). Tetapi jika Anda menggunakanfor i in "$@"; do echo $i; done
Anda akan mendapatkana⏎b c⏎d
.Saya menyadari ini telah dijawab dengan baik tetapi inilah perbandingan antara "$ @" $ @ "$ *" dan $ *
Isi skrip uji:
Sekarang, jalankan skrip pengujian dengan berbagai argumen:
sumber
Hanya berpikir ini mungkin sedikit lebih berguna ketika mencoba menguji bagaimana args masuk ke skrip Anda
sumber
$#
""
,''
sebagai argumen, juga jika tidak ada args itu diam. Saya mencoba untuk memperbaikinya, tetapi membutuhkan for for loop dan counter$#
. Saya baru saja menambahkan ini di akhir:echo "End of args or received quoted null"
SUN Unix saya memiliki banyak batasan, bahkan "$ @" tidak diartikan seperti yang diinginkan. Solusi saya adalah $ {@}. Sebagai contoh,
Omong-omong, saya harus memiliki skrip khusus ini karena Unix saya juga tidak mendukung grep -r
sumber
ksh
Jika Anda memasukkan
$@
string yang dikutip dengan karakter lain, tingkah lakunya sangat aneh ketika ada beberapa argumen, hanya argumen pertama yang disertakan di dalam tanda kutip.Contoh:
Hasil:
Tapi pertama-tama menugaskan ke variabel yang berbeda:
Hasil:
sumber
"$@"
di bash. Ini juga membantu menggambarkan perbedaan utama antara$@
dan$*
, dan mengapa keduanya berguna. Daribash(1)
halaman manual bagian Parameter Khusus: "*
- Ketika ekspansi terjadi dalam tanda kutip ganda, itu berkembang menjadi satu kata dengan nilai setiap parameter [...] Artinya,"$*"
sama dengan"$1c$2c..."
, di manac
[$IFS
]." Dan memang, menggunakan$*
bukannya$@
dalam contoh pertama Anda akan sudah terjaring keluaran identik dengan versi kedua."$@"
. Lagi dari halaman manual: "@
- Ketika ekspansi terjadi dalam tanda kutip ganda, setiap parameter meluas ke kata yang terpisah. Artinya,"$@"
setara dengan"$1"
"$2"
... Jika ekspansi kutip ganda terjadi dalam kata, ekspansi parameter pertama digabungkan dengan bagian awal dari kata aslinya, dan perluasan dari parameter terakhir digabungkan dengan bagian terakhir dari kata aslinya. " ... Dan memang, jika kode Anda telahbash -c "true foo $@ bar baz"
, maka jalankan itutest.sh one two
akan bersihbash -c 'true foo one' 'two bar baz'
.$*
, saya sepertinya lupa bahwa itu ada ..$@
baru mendapatkan traksi ketika saya pertama kali mulai scripting shell, saya masih harus mengingatkan diri saya ada di sana. Itu umum untuk"$*"
digunakan dalam skrip ... maka penulis akan menyadari bahwa itu menghancurkan semua argumen mereka bersama-sama, jadi mereka akan mencoba segala macam omong kosong yang kompleks dengan pemisahan kata"$*"
, atau [kembali] menyusun daftar arg dengan mengulang lebihshift
menarik mereka satu per satu ... hanya menggunakan$@
memecahkan itu. (Membantu bash menggunakan mnemonic yang sama untuk mengakses anggota array, juga:${var[*]}
untuk mereka semua sebagai kata,${var[@]}
untuk daftar kata.)bash -c
cara yang sama sekali tidak masuk akal.Kadang-kadang Anda ingin memberikan semua argumen Anda, tetapi didahului dengan bendera (misalnya
--flag
)Anda dapat melakukan ini dengan cara berikut:
Catatan: untuk menghindari pemisahan bidang ekstra, Anda harus mengutip
%s
dan$@
, dan untuk menghindari memiliki string tunggal, Anda tidak dapat mengutip subshell dariprintf
.sumber
Berfungsi dengan baik, kecuali jika Anda memiliki spasi atau karakter yang lolos. Saya tidak menemukan cara untuk menangkap argumen dalam kasus ini dan mengirim ke ssh di dalam skrip.
Ini bisa bermanfaat tetapi sangat jelek
sumber
Banyak jawaban di sini merekomendasikan
$@
atau$*
dengan dan tanpa tanda kutip, namun sepertinya tidak ada yang menjelaskan apa yang sebenarnya dilakukan dan mengapa Anda harus seperti itu. Jadi izinkan saya mencuri ringkasan yang sangat bagus ini dari jawaban ini :Perhatikan bahwa kutipan membuat semua perbedaan dan tanpa keduanya keduanya memiliki perilaku yang identik.
Untuk tujuan saya, saya perlu meneruskan parameter dari satu skrip ke skrip lain apa adanya dan untuk itu pilihan terbaik adalah:
Perhatikan tidak ada kutipan dan
$@
harus berfungsi juga dalam situasi di atas.sumber
bar "$@"
akan setara denganbar "$1" "$2" "$3" "$4"
Perhatikan bahwa tanda kutip itu penting!
"$@"
,$@
,"$*"
Atau$*
masing-masing akan berperilaku sedikit berbeda mengenai melarikan diri dan Rangkaian seperti yang dijelaskan dalam jawaban stackoverflow .Satu use case yang terkait erat adalah memberikan semua argumen di dalam argumen seperti ini:
bash -c "bar \"$1\" \"$2\" \"$3\" \"$4\""
.Saya menggunakan variasi jawaban @ kvantour untuk mencapai ini:
bash -c "bar $(printf -- '"%s" ' "$@")"
sumber