Apa yang dapat Anda lakukan dengan eval
perintah itu? Mengapa ini bermanfaat? Apakah ini semacam fungsi bawaan di bash? Tidak ada man
halaman untuk itu ..
help eval
untuk mendapatkan halaman "man" dari shell Anda
Apa yang dapat Anda lakukan dengan eval
perintah itu? Mengapa ini bermanfaat? Apakah ini semacam fungsi bawaan di bash? Tidak ada man
halaman untuk itu ..
help eval
untuk mendapatkan halaman "man" dari shell Anda
Jawaban:
eval
adalah bagian dari POSIX. Ini adalah antarmuka yang bisa menjadi shell built-in.
Ini dijelaskan dalam "Manual Programmer POSIX": http://www.unix.com/man-page/posix/1posix/eval/
eval - construct command by concatenating arguments
Itu akan mengambil argumen dan membangun perintah itu, yang akan dieksekusi oleh shell. Ini adalah contoh halaman manual:
1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
$foo
dengan nilai '10'
dan $x
dengan nilai 'foo'
.$y
, yang terdiri dari string '$foo'
. Tanda dolar harus diloloskan '$'
.echo $y
,.'$foo'
eval
. Pertama-tama akan mengevaluasi $x
ke string 'foo'
. Sekarang kami memiliki pernyataan y=$foo
yang akan dievaluasi y=10
.echo $y
sekarang nilainya '10'
.Ini adalah fungsi umum dalam banyak bahasa, misalnya Perl dan JavaScript. Lihat perldoc eval untuk lebih banyak contoh: http://perldoc.perl.org/functions/eval.html
eval
adalah fungsi bawaan, bukan fungsi. Dalam praktiknya, built-in berperilaku sangat mirip fungsi yang tidak memiliki definisi dalam bahasa, tetapi tidak cukup (seperti yang terlihat jika Anda cukup terpelintir untuk mendefinisikan fungsi yang disebut eval
).
Ya, eval
adalah perintah internal bash sehingga dijelaskan di bash
halaman manual.
eval [arg ...]
The args are read and concatenated together into a single com-
mand. This command is then read and executed by the shell, and
its exit status is returned as the value of eval. If there are
no args, or only null arguments, eval returns 0.
Biasanya ini digunakan dalam kombinasi dengan Substitusi Perintah . Tanpa eksplisit eval
, shell mencoba mengeksekusi hasil substitusi perintah, bukan untuk mengevaluasinya .
Katakan bahwa Anda ingin kode yang setara dengan VAR=value; echo $VAR
. Perhatikan perbedaan dalam bagaimana shell menangani tulisan-tulisan echo VAR=value
:
andcoz@...:~> $( echo VAR=value )
bash: VAR=value: command not found
andcoz@...:~> echo $VAR
<empty line>
Shell mencoba menjalankan echo
dan VAR=value
sebagai dua perintah terpisah. Itu melempar kesalahan tentang string kedua. Tugas ini tetap tidak efektif.
andcoz@...:~> eval $( echo VAR=value )
andcoz@...:~> echo $VAR
value
Shell menggabungkan (menggabungkan) dua string echo
dan VAR=value
, mem-parsing unit tunggal ini sesuai dengan aturan yang sesuai dan mengeksekusinya.Last but not least, eval
bisa menjadi perintah yang sangat berbahaya. Setiap input ke suatu eval
perintah harus diperiksa dengan cermat untuk menghindari masalah keamanan.
eval
tidak memiliki halaman manual karena itu bukan perintah eksternal yang terpisah, melainkan sebuah shell built-in, artinya perintah internal dan hanya diketahui oleh shell ( bash
). Bagian yang relevan dari bash
halaman manual mengatakan:
eval [arg ...]
The args are read and concatenated together into a single command.
This command is then read and executed by the shell, and its exit
status is returned as the value of eval. If there are no args, or only
null arguments, eval returns 0
Selain itu, keluarannya help eval
adalah:
eval: eval [arg ...]
Execute arguments as a shell command.
Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.
Exit Status:
Returns exit status of command or success if command is null.
eval
adalah perintah yang kuat dan jika Anda bermaksud menggunakannya Anda harus sangat berhati-hati untuk menghindari kemungkinan risiko keamanan yang menyertainya.
Pernyataan eval memberitahu shell untuk mengambil argumen eval sebagai perintah dan menjalankannya melalui command-line. Ini berguna dalam situasi seperti di bawah ini:
Dalam skrip Anda jika Anda mendefinisikan perintah menjadi variabel dan kemudian Anda ingin menggunakan perintah itu maka Anda harus menggunakan eval:
/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >
ls | more
. Dengan kata lain: Nama perintah tunggal terdiri dari sembilan karakter, termasuk spasi dan simbol pipa .
eval adalah perintah shell yang biasanya diimplementasikan sebagai builtin.
Dalam POSIX itu terdaftar sebagai bagian dari "2.14. Utilitas Built-In Khusus" di entri "eval" .
Yang dimaksud dengan builtin adalah:
Istilah "bawaan" menyiratkan bahwa shell dapat menjalankan utilitas secara langsung dan tidak perlu mencarinya.
Secara sederhana: buat jalur input untuk diuraikan dua kali .
Shell memiliki urutan langkah-langkah yang diikuti untuk "memproses" suatu garis. Anda dapat melihat gambar ini dan menyadari bahwa eval adalah satu-satunya garis yang naik, kembali ke langkah 1, di sebelah kiri. Dari deskripsi POSIX :
2.1 Pendahuluan Shell
- Shell membaca inputnya ....
- Shell memecah input menjadi token: kata dan operator
- Shell mem-parsing input menjadi perintah sederhana dan majemuk.
- Shell melakukan berbagai ekspansi (secara terpisah) ...
- Shell melakukan pengalihan dan menghapus operator pengalihan dan operan mereka dari daftar parameter.
- Shell mengeksekusi fungsi, built-in, file yang dapat dieksekusi, atau skrip ...
- Shell secara opsional menunggu perintah untuk menyelesaikan dan mengumpulkan status keluar.
Pada langkah 6 built-in akan dijalankan.
Pada langkah 6 eval menyebabkan baris yang diproses dikirim kembali ke langkah 1.
Ini adalah satu-satunya kondisi di mana urutan eksekusi kembali.
Itu sebabnya saya katakan: Dengan eval, garis input diurai dua kali .
Dan efek paling penting untuk dipahami. Apakah itu salah satu konsekuensi dari pertama kali sebuah baris tunduk pada tujuh langkah shell yang ditunjukkan di atas, mengutip . Di dalam langkah 4 (ekspansi), ada juga serangkaian langkah untuk melakukan semua ekspansi , yang terakhir adalah Penghapusan Kutipan :
Penghapusan kutipan akan selalu dilakukan terakhir.
Jadi, selalu, ada satu tingkat kutipan yang dihapus.
Sebagai konsekuensi dari efek pertama itu, bagian tambahan / berbeda dari garis menjadi terkena penguraian shell dan semua langkah lainnya.
Itu memungkinkan untuk melakukan ekspansi tidak langsung:
a=b b=c ; eval echo \$$a ### shall produce "c"
Mengapa? Karena pada loop pertama, yang pertama $
dikutip.
Karena itu, diabaikan untuk ekspansi oleh shell.
Selanjutnya $
dengan nama a diperluas untuk menghasilkan "b".
Kemudian, satu tingkat kutipan dihapus, membuat kutipan pertama $
.
Akhir dari loop pertama.
Kemudian, pada loop kedua string $b
tersebut dibaca oleh shell.
Kemudian diperluas ke "c"
Dan diberikan sebagai argumen untuk echo
.
Untuk "melihat" eval apa yang akan dihasilkan pada loop pertama (untuk dievaluasi lagi), gunakan gema. Atau perintah / skrip / program yang dengan jelas menunjukkan argumen:
$ a=b b=c
$ eval echo \$$a;
c
Ganti eval dengan echo untuk "melihat" apa yang terjadi:
$ echo echo \$$a
echo $b
Dimungkinkan juga untuk menampilkan semua "bagian" dari sebuah baris dengan:
$ printf '<%s> ' echo \$$a
<echo> <$b>
Yang, dalam contoh ini, hanya satu gema dan satu variabel, tetapi ingat untuk membantu dalam mengevaluasi kasus yang lebih kompleks.
Harus dikatakan bahwa: ada kesalahan dalam kode di atas, dapatkah Anda melihatnya ?.
Mudah: ada beberapa kutipan yang hilang.
Bagaimana? Anda mungkin bertanya. Sederhana, mari kita ubah variabel (bukan kode):
$ a=b b="hi jk"
$ eval echo \$$a
hi jk
Lihat ruang yang hilang?
Itu karena nilai di dalamnya $b
terpecah oleh shell.
Jika itu tidak meyakinkan Anda, coba ini:
$ a=b b="hi * jk"
$ eval echo \$$a ### warning this will expand to the list
### of all files in the present directory.
Kutipan tidak ada. Untuk membuatnya berfungsi dengan benar (tambahkan kutipan internal "$a"
dan eksternal \"
).
Coba ini (sangat aman):
$ a=b b="hi * jk"
$ eval echo \" \$"$a" \"
hi * jk
Tidak ada halaman manual untuk itu ..
Tidak, tidak ada halaman manual independen untuk ini. Pencarian manual dengan man -f eval
atau bahkan apropos eval
tidak menunjukkan entri.
Itu termasuk di dalamnya man bash
. Seperti halnya built-in.
Cari "SHELL BUILTIN COMMANDS" dan kemudian "eval".
Cara yang lebih mudah untuk mendapatkan bantuan adalah: Dalam bash, Anda bisa melakukannya help eval
untuk melihat bantuan untuk built-in.
Karena itu mengikat teks ke kode secara dinamis.
Dengan kata lain: ia mengubah daftar argumennya (dan / atau perluasan argumen semacam itu) menjadi baris yang dieksekusi. Jika karena alasan apa pun, argumen telah ditetapkan oleh penyerang, Anda akan mengeksekusi kode penyerang.
Atau bahkan lebih sederhana, dengan eval Anda memberi tahu siapa pun yang mendefinisikan nilai satu atau beberapa argumen:
Ayo, duduk di sini dan ketik baris perintah apa pun, aku akan menjalankannya dengan kekuatanku.
Apakah itu berbahaya? Harus jelas bagi semua orang bahwa itu.
Aturan keamanan untuk eval harus:
Hanya jalankan eval pada variabel yang telah Anda berikan nilainya.
Baca lebih detail di sini .
eval
adalah fitur bahasa yang paling ditafsirkan ( TCL
, python
, ruby
...), tidak hanya kerang. Ini digunakan untuk mengevaluasi kode secara dinamis.
Dalam shell, ini diimplementasikan sebagai perintah builtin shell.
Pada dasarnya, eval
mengambil string sebagai argumen dan mengevaluasi / menginterpretasikan kode di dalamnya. Dalam shell, eval
dapat mengambil lebih dari satu argumen, tetapi eval
hanya menggabungkan mereka untuk membentuk string untuk dievaluasi.
Ini sangat kuat karena Anda dapat membuat kode secara dinamis dan menjalankannya, sesuatu yang tidak dapat Anda lakukan dalam bahasa yang dikompilasi seperti C.
Suka:
varname=$1 varvalue=$2
eval "$varname=\$varvalue" # evaluate a string like "foo=$varvalue"
# which in Bourne-like shell language
# is a variable assignment.
Tapi itu juga berbahaya karena penting untuk membersihkan bagian dinamis (yang disediakan secara eksternal) dari apa yang diteruskan eval
untuk alasan yang ditafsirkan sebagai kode shell.
Misalnya, di atas jika $1
ini evil-command; var
, eval
akan berakhir-up mengevaluasi evil-command; var=$varvalue
kode shell dan kemudian menjalankan bahwa evil-command
.
Kejahatan eval
sering dibesar-besarkan.
OKE, berbahaya, tapi setidaknya kita tahu itu berbahaya.
Banyak perintah lain akan mengevaluasi Kode shell di argumen jika tidak dibersihkan, seperti (tergantung pada shell), [
alias test
, export
, printf
, GNU sed
, awk
dan tentu saja sh
/ bash
/ perl
dan semua penafsir ...
Contoh (di sini menggunakan uname
data yang tidak bersih evil-command
dan $a
disediakan secara eksternal):
$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux
$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"
Linux
$ a=';uname'; sh -c "echo $a"
Linux
Itu sed
, export
... perintah dapat dianggap lebih berbahaya karena sementara itu jelas eval "$var"
akan menyebabkan konten $var
dievaluasi sebagai kode shell, itu tidak begitu jelas dengan sed "s/foo/$var/"
atau export "$var=value"
atau [ "$var" -gt 0 ]
. Bahayanya sama, tetapi tersembunyi dalam perintah-perintah lainnya.
sed
seperti eval
sedang melewati string yang terkandung dalam variabel, dan untuk keduanya, isi string itu akhirnya dievaluasi sebagai kode shell, jadi sed
sama berbahayanya dengan eval
, itulah yang saya katakan. sed
sedang melewati string yang mengandung uname
(uname belum dieksekusi sejauh ini) dan melalui doa sed
, perintah uname akhirnya dieksekusi. Seperti untuk eval. Di sed 's/foo/$a/g'
, Anda tidak meneruskan data yang tidak bersih ke sed
, bukan itu yang sedang kita bicarakan di sini.
Contoh ini dapat menjelaskan:
#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"
Output dari skrip di atas:
$VAR2
$VAR1
25
eval
. Apakah Anda percaya bahwa ada beberapa aspek mendasar dan kritis dari fungsi eval
yang tidak tercakup dalam jawaban yang ada? Jika demikian, maka jelaskan , dan gunakan contoh untuk menggambarkan penjelasan Anda. Tolong jangan menanggapi dalam komentar; edit jawaban Anda untuk membuatnya lebih jelas dan lebih lengkap.
type command
untuk mempelajari jenis perintah apa. (type eval
dalam kasus ini)