Apa perintah "eval" di bash?


176

Apa yang dapat Anda lakukan dengan evalperintah itu? Mengapa ini bermanfaat? Apakah ini semacam fungsi bawaan di bash? Tidak ada manhalaman untuk itu ..


28
Gunakan type commanduntuk mempelajari jenis perintah apa. ( type evaldalam kasus ini)
rozcietrzewiacz

9
"eval is a built-in shell"
Nuno Rafael Figueiredo

3
help evaluntuk mendapatkan halaman "man" dari shell Anda
m-ric

eval adalah bash-builtin dan didokumentasikan dalam halaman manual bash. Jadi cukup ketik "man bash" dan cari bagian yang sesuai untuk eval. Ini berlaku untuk bash-builtin lainnya juga.
Dirk Thannhäuser

Jawaban:


132

evaladalah 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
  1. Di baris pertama Anda mendefinisikan $foodengan nilai '10'dan $xdengan nilai 'foo'.
  2. Sekarang define $y, yang terdiri dari string '$foo'. Tanda dolar harus diloloskan '$'.
  3. Untuk memeriksa hasilnya echo $y,.
  4. Hasilnya adalah string '$foo'
  5. Sekarang kita ulangi tugas dengan eval. Pertama-tama akan mengevaluasi $xke string 'foo'. Sekarang kami memiliki pernyataan y=$fooyang akan dievaluasi y=10.
  6. Hasilnya echo $ysekarang 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


4
Dalam terminologi shell, evaladalah 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).
Gilles

thx, tetap itu :-)
echox

4
Apa perbedaan antara eval dan backticks `?
JohnyTex

5
Backticks adalah singkatan untuk mengeksekusi seluruh shell lain, yang berarti Anda akan memiliki proses bash / sh anak lain berjalan dalam skrip Anda.
Aaron R.

Mengapa echo $ y (tahap 3) mengembalikan foo (10) alih-alih $ foo? (Yaitu hanya nilai foo bukan string $ + nilai foo)?
JohnDoea

60

Ya, evaladalah perintah internal bash sehingga dijelaskan di bashhalaman 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:

  1. andcoz@...:~> $( echo VAR=value )
    bash: VAR=value: command not found
    andcoz@...:~> echo $VAR
    <empty line>
    

    Shell mencoba menjalankan echodan VAR=valuesebagai dua perintah terpisah. Itu melempar kesalahan tentang string kedua. Tugas ini tetap tidak efektif.

  2. andcoz@...:~> eval $( echo VAR=value )
    andcoz@...:~> echo $VAR
    value
    
    Shell menggabungkan (menggabungkan) dua string echodan VAR=value, mem-parsing unit tunggal ini sesuai dengan aturan yang sesuai dan mengeksekusinya.

Last but not least, evalbisa menjadi perintah yang sangat berbahaya. Setiap input ke suatu evalperintah harus diperiksa dengan cermat untuk menghindari masalah keamanan.


18

evaltidak 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 bashhalaman 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 evaladalah:

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.

evaladalah perintah yang kuat dan jika Anda bermaksud menggunakannya Anda harus sangat berhati-hati untuk menghindari kemungkinan risiko keamanan yang menyertainya.


16

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 >

3
Komentar pada baris 4 dari contoh Anda salah: Seharusnya "Perintah di atas tidak bekerja karena bash mencoba menemukan perintah yang disebut ls | more. Dengan kata lain: Nama perintah tunggal terdiri dari sembilan karakter, termasuk spasi dan simbol pipa .
CFI

Saya mendapatkan perilaku yang persis sama seperti yang dia laporkan. bash --version == GNU bash, versi 3.2.57 (1) -release (x86_64-apple-darwin18)
Alexander Bird

10

Apa itu eval?

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.

Apa fungsinya?

Secara sederhana: buat jalur input untuk diuraikan dua kali .

Bagaimana cara melakukannya?

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

  1. Shell membaca inputnya ....
  2. Shell memecah input menjadi token: kata dan operator
  3. Shell mem-parsing input menjadi perintah sederhana dan majemuk.
  4. Shell melakukan berbagai ekspansi (secara terpisah) ...
  5. Shell melakukan pengalihan dan menghapus operator pengalihan dan operan mereka dari daftar parameter.
  6. Shell mengeksekusi fungsi, built-in, file yang dapat dieksekusi, atau skrip ...
  7. 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 .

Efek parsing dua kali.

Pertama.

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.

Kedua.

Sebagai konsekuensi dari efek pertama itu, bagian tambahan / berbeda dari garis menjadi terkena penguraian shell dan semua langkah lainnya.

Contoh.

Tipuan.

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 $btersebut 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.

Koreksi.

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 $bterpecah 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.

Mengapa?

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

Tentang manual:

Tidak ada halaman manual untuk itu ..

Tidak, tidak ada halaman manual independen untuk ini. Pencarian manual dengan man -f evalatau bahkan apropos evaltidak 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 evaluntuk melihat bantuan untuk built-in.

Mengapa eval disebut jahat?

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 .


10

evaladalah 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, evalmengambil string sebagai argumen dan mengevaluasi / menginterpretasikan kode di dalamnya. Dalam shell, evaldapat mengambil lebih dari satu argumen, tetapi evalhanya 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 evaluntuk alasan yang ditafsirkan sebagai kode shell.

Misalnya, di atas jika $1ini evil-command; var, evalakan berakhir-up mengevaluasi evil-command; var=$varvaluekode shell dan kemudian menjalankan bahwa evil-command.

Kejahatan evalsering 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, awkdan tentu saja sh/ bash/ perldan semua penafsir ...

Contoh (di sini menggunakan unamedata yang tidak bersih evil-commanddan $adisediakan 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 $vardievaluasi 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.


@ Binzebra, sedseperti evalsedang melewati string yang terkandung dalam variabel, dan untuk keduanya, isi string itu akhirnya dievaluasi sebagai kode shell, jadi sedsama berbahayanya dengan eval, itulah yang saya katakan. sedsedang 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.
Stéphane Chazelas

2

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

Terima kasih atas kontribusi Anda, tetapi, walaupun sama menghiburnya, kami tidak benar-benar tertarik untuk menyusun daftar contoh penggunaan yang sedikit berbeda eval. Apakah Anda percaya bahwa ada beberapa aspek mendasar dan kritis dari fungsi evalyang 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.
Scott
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.