Pembaruan: Beberapa orang mengatakan seseorang harus-tidak pernah menggunakan eval. Saya tidak setuju. Saya pikir risikonya muncul ketika input yang korup dapat diteruskan eval
. Namun ada banyak situasi umum di mana itu bukan risiko, dan karena itu perlu diketahui bagaimana menggunakan eval dalam hal apa pun. Jawaban stackoverflow ini menjelaskan risiko eval dan alternatif eval. Pada akhirnya tergantung pada pengguna untuk menentukan apakah eval aman dan efisien untuk digunakan.
eval
Pernyataan bash memungkinkan Anda untuk mengeksekusi baris kode yang dihitung atau diperoleh, dengan skrip bash Anda.
Mungkin contoh yang paling mudah adalah program bash yang membuka skrip bash lain sebagai file teks, membaca setiap baris teks, dan menggunakan eval
untuk mengeksekusinya secara berurutan. Itu pada dasarnya perilaku yang sama dengan source
pernyataan bash , yang akan digunakan orang, kecuali jika diperlukan untuk melakukan semacam transformasi (misalnya penyaringan atau substitusi) pada konten skrip yang diimpor.
Saya jarang membutuhkannya eval
, tetapi saya merasa berguna untuk membaca atau menulis variabel yang namanya terkandung dalam string yang ditugaskan ke variabel lain. Misalnya, untuk melakukan tindakan pada set variabel, sambil menjaga kode jejak kecil dan menghindari redundansi.
eval
secara konseptual sederhana. Namun, sintaks yang ketat dari bahasa bash, dan urutan parsing penerjemah bash dapat diberi nuansa dan membuatnya eval
tampak samar dan sulit untuk digunakan atau dipahami. Berikut ini yang penting:
Argumen yang diteruskan ke eval
adalah ekspresi string yang dihitung pada saat runtime. eval
akan mengeksekusi hasil parsing terakhir dari argumennya sebagai baris kode aktual dalam skrip Anda.
Sintaks dan urutan parsing ketat. Jika hasilnya bukan baris kode bash yang dapat dieksekusi, dalam lingkup skrip Anda, program akan macet pada eval
pernyataan saat mencoba mengeksekusi sampah.
Saat menguji Anda dapat mengganti eval
pernyataan dengan echo
dan melihat apa yang ditampilkan. Jika itu kode yang sah dalam konteks saat ini, menjalankannya eval
akan berhasil.
Contoh-contoh berikut dapat membantu menjelaskan bagaimana eval bekerja ...
Contoh 1:
eval
pernyataan di depan kode 'normal' adalah NOP
$ eval a=b
$ eval echo $a
b
Dalam contoh di atas, eval
pernyataan pertama tidak memiliki tujuan dan dapat dihilangkan. eval
tidak ada gunanya di baris pertama karena tidak ada aspek dinamis untuk kode, yaitu sudah diuraikan ke dalam baris akhir kode bash, sehingga akan sama dengan pernyataan kode normal dalam skrip bash. -2 eval
ada gunanya juga, karena, meskipun ada langkah parsing mengkonversi $a
ke setara string literal nya, tidak ada tipuan (misalnya tidak ada referensi melalui nilai string dari yang sebenarnya benda bash atau variabel bash script-diadakan), sehingga akan berperilaku identik sebagai baris kode tanpa eval
awalan.
Contoh 2:
Melakukan penugasan var menggunakan nama var yang diteruskan sebagai nilai string.
$ key="mykey"
$ val="myval"
$ eval $key=$val
$ echo $mykey
myval
Jika Anda melakukannya echo $key=$val
, hasilnya adalah:
mykey=myval
Bahwa , sebagai hasil akhir dari penguraian string, adalah apa yang akan dieksekusi oleh eval, maka hasil dari pernyataan echo di akhir ...
Contoh 3:
Menambahkan lebih banyak tipuan ke Contoh 2
$ keyA="keyB"
$ valA="valB"
$ keyB="that"
$ valB="amazing"
$ eval eval \$$keyA=\$$valA
$ echo $that
amazing
Di atas sedikit lebih rumit dari contoh sebelumnya, lebih bergantung pada urutan parsing dan kekhasan bash. The eval
garis akan kira-kira bisa diurai secara internal dalam urutan sebagai berikut (perhatikan pernyataan berikut pseudocode, bukan kode nyata, hanya untuk mencoba untuk menunjukkan bagaimana pernyataan akan mendapatkan dipecah menjadi langkah-langkah internal untuk sampai pada hasil akhir) .
eval eval \$$keyA=\$$valA # substitution of $keyA and $valA by interpreter
eval eval \$keyB=\$valB # convert '$' + name-strings to real vars by eval
eval $keyB=$valB # substitution of $keyB and $valB by interpreter
eval that=amazing # execute string literal 'that=amazing' by eval
Jika asumsi penguraian tidak menjelaskan apa yang dilakukan eval cukup, contoh ketiga dapat menjelaskan penguraian lebih detail untuk membantu memperjelas apa yang sedang terjadi.
Contoh 4:
Temukan apakah vars, yang namanya terkandung dalam string, sendiri mengandung nilai string.
a="User-provided"
b="Another user-provided optional value"
c=""
myvarname_a="a"
myvarname_b="b"
myvarname_c="c"
for varname in "myvarname_a" "myvarname_b" "myvarname_c"; do
eval varval=\$$varname
if [ -z "$varval" ]; then
read -p "$varname? " $varname
fi
done
Dalam iterasi pertama:
varname="myvarname_a"
Bash mem-parsing argumen ke eval
, dan eval
melihat ini secara harfiah pada saat runtime:
eval varval=\$$myvarname_a
Pseudocode berikut ini mencoba menggambarkan bagaimana bash menginterpretasikan baris kode real di atas , untuk sampai pada nilai akhir yang dieksekusi oleh eval
. (baris berikut deskriptif, bukan kode bash yang tepat):
1. eval varval="\$" + "$varname" # This substitution resolved in eval statement
2. .................. "$myvarname_a" # $myvarname_a previously resolved by for-loop
3. .................. "a" # ... to this value
4. eval "varval=$a" # This requires one more parsing step
5. eval varval="User-provided" # Final result of parsing (eval executes this)
Setelah semua penguraian selesai, hasilnya adalah apa yang dieksekusi, dan efeknya jelas, menunjukkan tidak ada yang misterius tentang eval
dirinya sendiri, dan kompleksitasnya adalah penguraian argumennya.
varval="User-provided"
Kode yang tersisa dalam contoh di atas hanya menguji untuk melihat apakah nilai yang ditetapkan untuk $ varval adalah nol, dan, jika demikian, meminta pengguna untuk memberikan nilai.
$($n)
berjalan$n
dalam subkulit. Mencoba menjalankan perintah1
yang tidak ada.