Saya membaca skrip bash yang dibuat seseorang dan saya perhatikan bahwa penulis tidak menggunakan eval untuk mengevaluasi variabel sebagai perintah yang
digunakan penulis
bash -c "$1"
dari pada
eval "$1"
Saya berasumsi menggunakan eval adalah metode yang disukai dan mungkin juga lebih cepat. Benarkah?
Apakah ada perbedaan praktis antara keduanya? Apa perbedaan penting antara keduanya?
bash
shell-script
bash-script
siapa saya
sumber
sumber
e='echo foo'; $e
berfungsi dengan baik.Jawaban:
eval "$1"
mengeksekusi perintah dalam skrip saat ini. Itu dapat mengatur dan menggunakan variabel shell dari skrip saat ini, mengatur variabel lingkungan untuk skrip saat ini, mengatur dan menggunakan fungsi dari skrip saat ini, mengatur direktori saat ini, umask, batas dan atribut lainnya untuk skrip saat ini, dan sebagainya.bash -c "$1"
mengeksekusi perintah dalam skrip yang benar-benar terpisah, yang mewarisi variabel lingkungan, deskriptor file dan lingkungan proses lainnya (tetapi tidak mengirimkan perubahan apa pun kembali) tetapi tidak mewarisi pengaturan shell internal (variabel shell, fungsi, opsi, jebakan, dll.).Ada cara lain
(eval "$1")
, yang mengeksekusi perintah dalam sebuah subkulit: ia mewarisi segalanya dari skrip panggilan tetapi tidak mengirimkan perubahan apa pun kembali.Misalnya, dengan asumsi bahwa variabel
dir
tidak diekspor dan$1
adalahcd "$foo"; ls
, maka:cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
daftar isi/somewhere/else
dan cetakan/somewhere/else
.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
daftar isi/somewhere/else
dan cetakan/starting/directory
.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
daftar konten/starting/directory
(karenacd ""
tidak mengubah direktori saat ini) dan mencetak/starting/directory
.sumber
(eval "$1")
tidak ada hubungannya dengansource
. Itu hanya kombinasi dari(…)
daneval
.source foo
kira-kira setara denganeval "$(cat foo)"
.eval
dan.dot
adalah yangeval
berfungsi dengan argumen dan.dot
bekerja dengan file.Perbedaan paling penting di antara keduanya
Dan
Apakah yang pertama berjalan dalam subkulit dan yang terakhir tidak. Begitu:
KELUARAN:
KELUARAN:
Saya tidak tahu mengapa ada orang yang menggunakan executable
bash
seperti itu. Jika Anda harus memintanya, gunakan POSIX built-in dijaminsh
. Atau(subshell eval)
jika Anda ingin melindungi lingkungan Anda.Secara pribadi, saya lebih suka shell di
.dot
atas segalanya.KELUARAN
TETAPI ANDA BUTUHKAN?
Satu-satunya alasan untuk menggunakan salah satunya adalah jika variabel Anda benar-benar menetapkan atau mengevaluasi yang lain, atau pemisahan kata penting untuk output.
Contohnya:
KELUARAN:
Itu bekerja, tetapi hanya karena
echo
tidak peduli dengan argumennya.KELUARAN:
Lihat? Tanda kutip ganda muncul karena hasil ekspansi shell
$var
tidak dievaluasiquote-removal
.KELUARAN:
Tetapi dengan
eval
ataush
:KELUARAN:
Ketika kita menggunakan
eval
ataush
shell mengambil pass kedua pada hasil ekspansi dan mengevaluasinya sebagai perintah potensial juga, dan dengan demikian tanda kutip membuat perbedaan. Anda juga dapat melakukan:KELUARAN
sumber
Saya melakukan tes cepat:
(Ya, saya tahu, saya menggunakan bash -c untuk mengeksekusi loop tetapi itu seharusnya tidak membuat perbedaan).
Hasil:
Jadi
eval
lebih cepat. Dari halaman manual darieval
:bash -c
tentu saja, jalankan perintah dalam bash shell. Satu catatan: Saya menggunakan/bin/echo
karenaecho
shell built-in denganbash
, yang berarti proses baru tidak perlu dimulai. Mengganti/bin/echo
denganecho
untukbash -c
tes, butuh1.28s
. Itu hampir sama. Hovever,eval
lebih cepat untuk menjalankan executables. Perbedaan utama di sini adalah bahwaeval
tidak memulai shell baru (itu mengeksekusi perintah di saat ini) sedangkanbash -c
memulai shell baru, kemudian mengeksekusi perintah di shell baru. Memulai shell baru membutuhkan waktu, dan itulah sebabnyabash -c
lebih lambat daripadaeval
.sumber
bash -c
denganeval
tidakexec
.bash -c
tidak terlalu buruk ...