eval
dan exec
keduanya dibangun di perintah bash (1) yang menjalankan perintah.
Saya juga melihat exec
ada beberapa opsi tetapi apakah itu satu-satunya perbedaan? Apa yang terjadi pada konteks mereka?
bash
shell
shell-builtin
Willian Paixao
sumber
sumber
Jawaban:
eval
danexec
binatang yang sama sekali berbeda. (Terlepas dari kenyataan bahwa keduanya akan menjalankan perintah, tetapi demikian juga semua yang Anda lakukan dalam sebuah shell.)Apa yang
exec cmd
dilakukan, persis sama dengan hanya menjalankancmd
, kecuali bahwa shell saat ini diganti dengan perintah, alih-alih proses terpisah dijalankan. Secara internal, running say/bin/ls
akan memanggilfork()
untuk membuat proses anak, dan kemudianexec()
pada anak untuk mengeksekusi/bin/ls
.exec /bin/ls
di sisi lain tidak akan bercabang, tetapi hanya mengganti shell.Membandingkan:
dengan
echo $$
mencetak PID dari shell yang saya mulai, dan listing/proc/self
memberi kita PID darils
yang dijalankan dari shell. Biasanya, ID proses berbeda, tetapi denganexec
shell danls
memiliki ID proses yang sama. Juga, perintah berikutexec
tidak berjalan, karena shell diganti.Di samping itu:
eval
akan menjalankan argumen sebagai perintah di shell saat ini. Dengan kata laineval foo bar
sama dengan adilfoo bar
. Tetapi variabel akan diperluas sebelum dieksekusi, sehingga kami dapat mengeksekusi perintah yang disimpan dalam variabel shell:Itu tidak akan membuat proses anak, sehingga variabel diatur dalam shell saat ini. (Tentu saja
eval /bin/ls
akan menciptakan proses anak, seperti yang dilakukan oleh orang tua biasa/bin/ls
.)Atau kita bisa memiliki perintah yang menampilkan perintah shell. Menjalankan
ssh-agent
memulai agen di latar belakang, dan menghasilkan banyak tugas variabel, yang dapat diatur dalam shell saat ini dan digunakan oleh proses anak (ssh
perintah yang akan Anda jalankan). Makassh-agent
dapat dimulai dengan:Dan shell saat ini akan mendapatkan variabel untuk mewarisi perintah lain.
Tentu saja, jika variabel tersebut
cmd
mengandung sesuatu sepertirm -rf $HOME
, maka menjalankaneval "$cmd"
bukan sesuatu yang ingin Anda lakukan. Bahkan hal-hal seperti penggantian perintah di dalam string akan diproses, jadi orang harus benar - benar yakin bahwa input keeval
aman sebelum menggunakannya.Seringkali, mungkin untuk menghindari
eval
dan menghindari bahkan secara tidak sengaja mencampur kode dan data dengan cara yang salah.sumber
eval
di tempat pertama untuk jawaban ini juga. Hal-hal seperti memodifikasi variabel secara tidak langsung dapat dilakukan di banyak shell melaluideclare
/typeset
/nameref
dan ekspansi seperti${!var}
, jadi saya akan menggunakan itu alih-aliheval
kecuali saya benar-benar harus menghindarinya.exec
tidak membuat proses baru. Ini menggantikan proses saat ini dengan perintah baru. Jika Anda melakukan ini pada baris perintah maka itu akan secara efektif mengakhiri sesi shell Anda (dan mungkin mengeluarkan Anda atau menutup jendela terminal!)misalnya
Di sini saya di
ksh
(shell normal saya). Aku mulaibash
dan kemudian di dalam bash Sayaexec /bin/echo
. Kita dapat melihat bahwa saya telah dikembalikan keksh
setelah itu karenabash
prosesnya diganti oleh/bin/echo
.sumber
TL; DR
exec
digunakan untuk mengganti proses shell saat ini dengan yang baru dan menangani aliran redirection / deskriptor file jika tidak ada perintah yang ditentukan.eval
digunakan untuk mengevaluasi string sebagai perintah. Keduanya dapat digunakan untuk membangun dan mengeksekusi perintah dengan argumen yang dikenal saat run-time, tetapiexec
menggantikan proses shell saat ini di samping mengeksekusi perintah.exec buil-in
Sintaksis:
Menurut manual jika ada perintah yang ditentukan ini built-in
Dengan kata lain, jika Anda menjalankan
bash
dengan PID 1234 dan jika Anda menjalankan diexec top -u root
dalam shell itu,top
perintah kemudian akan memiliki PID 1234 dan mengganti proses shell Anda.Di mana ini berguna? Dalam sesuatu yang dikenal sebagai skrip wrapper. Script tersebut membangun kumpulan argumen atau membuat keputusan tertentu tentang variabel apa yang harus dilewatkan ke lingkungan, dan kemudian digunakan
exec
untuk menggantikan dirinya dengan perintah apa pun yang ditentukan, dan tentu saja memberikan argumen yang sama dengan yang dibuat oleh skrip wrapper di sepanjang jalan.Apa yang manual juga nyatakan adalah:
Ini memungkinkan kita untuk mengarahkan ulang apa pun dari arus keluaran shells ke file. Ini mungkin berguna untuk tujuan logging atau penyaringan, di mana Anda tidak ingin melihat
stdout
perintah tetapi hanyastderr
. Misalnya, seperti:Perilaku ini membuatnya mudah untuk masuk dalam skrip shell , mengarahkan aliran untuk memisahkan file atau proses , dan hal - hal menyenangkan lainnya dengan deskriptor file.
Pada level kode sumber setidaknya untuk
bash
versi 4.3,exec
built-in didefinisikan dalambuiltins/exec.def
. Ini mem-parsing perintah yang diterima, dan jika ada, itu meneruskan hal-hal keshell_execve()
fungsi yang didefinisikan dalamexecute_cmd.c
file.Singkatnya, ada keluarga
exec
perintah dalam bahasa pemrograman C, danshell_execve()
pada dasarnya adalah fungsi pembungkus dariexecve
:eval built-in
Manual bash 4.3 menyatakan (penekanan ditambahkan oleh saya):
Perhatikan bahwa tidak ada proses penggantian yang terjadi. Tidak seperti di
exec
mana tujuannya adalah untuk mensimulasikanexecve()
fungsionalitas,eval
built in hanya berfungsi untuk "mengevaluasi" argumen, sama seperti jika pengguna telah mengetiknya pada baris perintah. Dengan demikian, proses baru dibuat.Di mana ini mungkin berguna? Seperti yang ditunjukkan Gilles dalam jawaban ini , "... eval tidak sering digunakan. Dalam beberapa shell, penggunaan yang paling umum adalah untuk mendapatkan nilai dari variabel yang namanya tidak dikenal sampai runtime". Secara pribadi, saya telah menggunakannya dalam beberapa skrip di Ubuntu di mana perlu untuk mengeksekusi / mengevaluasi perintah berdasarkan ruang kerja spesifik yang saat ini digunakan pengguna.
Pada level kode sumber, ia didefinisikan di dalam
builtins/eval.def
dan meneruskan string input yang diuraikan untukevalstring()
berfungsi.Antara lain,
eval
dapat menetapkan variabel yang tetap dalam lingkungan eksekusi shell saat ini, sementaraexec
tidak dapat:sumber
Uh apa? Intinya
eval
adalah bahwa ia tidak dengan cara apa pun menciptakan proses anak. Jika aku melakukandalam sebuah shell, lalu setelah itu shell yang sekarang akan berubah direktori. Tidak
exec
membuat proses anak baru, melainkan mengubah executable saat ini (yaitu shell) untuk yang diberikan; id proses (dan buka file dan hal-hal lain) tetap sama. Berbeda denganeval
, sebuahexec
tidak akan kembali ke shell panggilan kecualiexec
itu sendiri gagal karena tidak dapat menemukan atau memuat executable atau mati untuk masalah ekspansi argumen.eval
pada dasarnya mengartikan argumennya sebagai string setelah concatenation, yaitu ia akan melakukan lapisan tambahan ekspansi wildcard dan pemisahan argumen.exec
tidak melakukan hal seperti itu.sumber
Evaluasi
Pekerjaan ini:
Namun, ini tidak:
Memproses penggantian gambar
Contoh ini menunjukkan bagaimana
exec
mengganti gambar proses pemanggilannya:Perhatikan bahwa
exec echo $$
dijalankan dengan PID dari subkulit! Selanjutnya, setelah selesai, kami kembali kesh$
cangkang asli kami .Di sisi lain,
eval
tidak bukan mengganti gambar proses. Sebaliknya, ia menjalankan perintah yang diberikan seperti yang biasanya Anda lakukan di dalam shell itu sendiri. (Tentu saja, jika Anda menjalankan perintah yang memerlukan proses untuk melahirkan ... itu tidak hanya itu!)sumber
exec
)