Saya menulis skrip yang dapat menghasilkan argumen untuk saya, dengan kutipan
Jika output dikutip dengan benar untuk shell, dan Anda mempercayai output , maka Anda bisa menjalankannya eval
.
Dengan anggapan Anda memiliki shell yang mendukung array, sebaiknya gunakan satu untuk menyimpan argumen yang Anda dapatkan.
Jika ./gen_args.sh
menghasilkan keluaran seperti 'foo bar' '*' asdf
, maka kita bisa menjalankan eval "args=( $(./gen_args.sh) )"
untuk mengisi array yang disebut args
dengan hasilnya. Itu akan menjadi tiga unsur foo bar
, *
, asdf
.
Kita dapat menggunakan "${args[@]}"
seperti biasa untuk memperluas elemen array secara individual:
$ eval "args=( $(./gen_args.sh) )"
$ for var in "${args[@]}"; do printf ":%s:\n" "$var"; done
:foo bar:
:*:
:asdf:
(Perhatikan tanda kutip. "${array[@]}"
Perluas ke semua elemen sebagai argumen berbeda yang tidak dimodifikasi. Tanpa tanda kutip, elemen array dapat mengalami pemisahan kata. Lihat misalnya halaman Array di BashGuide .)
Namun , eval
dengan senang hati akan menjalankan penggantian shell, jadi $HOME
di output akan diperluas ke direktori home Anda, dan substitusi perintah akan benar-benar menjalankan perintah di shell yang sedang berjalan eval
. Output dari "$(date >&2)"
akan membuat elemen array kosong tunggal dan mencetak tanggal saat ini di stdout. Ini menjadi masalah jika gen_args.sh
mendapat data dari beberapa sumber yang tidak dipercaya, seperti host lain melalui jaringan, nama file yang dibuat oleh pengguna lain. Outputnya bisa termasuk perintah sewenang-wenang. (Jika get_args.sh
itu sendiri berbahaya, tidak perlu mengeluarkan apa pun, itu bisa langsung menjalankan perintah jahat.)
Alternatif untuk mengutip shell, yang sulit diurai tanpa eval, adalah menggunakan beberapa karakter lain sebagai pemisah dalam output skrip Anda. Anda harus memilih satu yang tidak diperlukan dalam argumen yang sebenarnya.
Mari kita pilih #
, dan hasilkan skripnya foo bar#*#asdf
. Sekarang kita dapat menggunakan ekspansi perintah yang tidak dikutip untuk membagi output dari perintah ke argumen.
$ IFS='#' # split on '#' signs
$ set -f # disable globbing
$ args=( $( ./gen_args3.sh ) ) # assign the values to the array
$ for var in "${args[@]}"; do printf ":%s:\n" "$var"; done
:foo bar:
:*:
:asdf:
Anda harus mengatur IFS
kembali nanti jika Anda bergantung pada pemisahan kata di tempat lain dalam skrip ( unset IFS
harus berfungsi untuk menjadikannya default), dan juga gunakan set +f
jika Anda ingin menggunakan globbing nanti.
Jika Anda tidak menggunakan Bash atau shell lain yang memiliki array, Anda bisa menggunakan parameter posisi untuk itu. Ganti args=( $(...) )
dengan set -- $(./gen_args.sh)
dan gunakan "$@"
sebagai gantinya "${args[@]}"
. (Di sini, Anda juga perlu mengutip "$@"
, jika tidak, parameter posisi tunduk pada pemisahan kata.)
eval
dapat digunakan, tetapi umumnya tidak disarankan.xargs
adalah sesuatu yang perlu dipertimbangkan juga