Güncelleme: Bazı insanlar değerlendirmeyi asla kullanmamalı derler. Katılmıyorum. Bence risk, bozuk girdilere geçilebildiğinde ortaya çıkar eval
. Bununla birlikte, bunun bir risk olmadığı birçok yaygın durum vardır ve bu nedenle her durumda eval'ün nasıl kullanılacağını bilmeye değer. Bu yığın akışı cevabı , değerlendirmenin risklerini ve değerlendirmeye alternatifleri açıklar. Sonuç olarak, eval'ün güvenli ve etkili olup olmadığını / ne zaman kullanılacağını belirlemek kullanıcıya bağlıdır.
Bash eval
deyimi, bash betiğiniz tarafından hesaplanan veya alınan kod satırlarını yürütmenizi sağlar.
Belki de en açık örnek, başka bir bash betiğini metin dosyası olarak açan, her metin satırını okuyan ve eval
bunları sırayla yürütmek için kullanılan bir bash programı olabilir . Bu source
, içe aktarılan komut dosyasının içeriğinde bir tür dönüşüm (örn. Filtreleme veya ikame) gerçekleştirmek gerekmedikçe , bash ifadesiyle aynı davranıştır .
Nadiren ihtiyacım vardı eval
, ancak adları diğer değişkenlere atanan dizelerde bulunan değişkenleri okumak veya yazmak için yararlı buldum . Örneğin, kod ayak izini küçük tutarken ve fazlalıktan kaçınırken, değişken kümeleri üzerinde eylemler gerçekleştirmek için.
eval
kavramsal olarak basittir. Bununla birlikte, bash dilinin sıkı sözdizimi ve bash tercümanının ayrıştırma sırası nüanslanabilir ve eval
şifreli ve kullanımı veya anlaşılması zor görünebilir. İşte temel bilgiler:
Aktarılan bağımsız değişken , çalışma zamanında hesaplanan eval
bir dize ifadesidir . eval
argümanının nihai çözümlü sonucunu , kodunuzda gerçek bir kod satırı olarak yürütür .
Sözdizimi ve ayrıştırma sırası katıdır. Sonuç, yürütülebilir bir bash kodu satırı değilse, komut dosyanızın kapsamında, program, eval
çöp işlemini yürütmeye çalışırken ifadede kilitlenir .
Test sırasında eval
ifadeyi değiştirebilir echo
ve neyin görüntülendiğine bakabilirsiniz. Geçerli bağlamda meşru bir kod ise, onu çalıştırmak eval
işe yarayacaktır.
Aşağıdaki örnekler, değerlendirmenin nasıl çalıştığını netleştirmeye yardımcı olabilir ...
Örnek 1:
eval
'normal' kodun önündeki ifade bir NOP
$ eval a=b
$ eval echo $a
b
Yukarıdaki örnekte, ilk eval
ifadelerin bir amacı yoktur ve ortadan kaldırılabilir. eval
ilk satırda anlamsızdır, çünkü kodun dinamik bir yönü yoktur, yani zaten bash kodunun son satırlarına ayrıştırılmıştır, bu nedenle bash komut dosyasında normal bir kod ifadesi ile aynı olacaktır. 2 eval
dönüştürme bir ayrıştırma adımı olmasına rağmen, çünkü çok anlamsız $a
onun değişmez dize eşdeğer, hiçbir indirection yoktur (örneğin bir dize değeri yoluyla hiçbir referans gerçek bash isim veya bash-bekletilen komut değişkeni), bu aynı şekilde davranması diye eval
öneki olmayan bir kod satırı olarak .
Örnek 2:
Dize değerleri olarak iletilen var adlarını kullanarak var ataması gerçekleştirin.
$ key="mykey"
$ val="myval"
$ eval $key=$val
$ echo $mykey
myval
Eğer olsaydınız echo $key=$val
, çıktı şu olurdu:
mykey=myval
Yani , string ayrıştırma nihai sonucu olan, eval tarafından sonunda yankı ifadesinin dolayısıyla sonucunu çalıştırılacaktır budur ...
Örnek 3:
Örnek 2'ye daha fazla dolaylı ekleme
$ keyA="keyB"
$ valA="valB"
$ keyB="that"
$ valB="amazing"
$ eval eval \$$keyA=\$$valA
$ echo $that
amazing
Yukarıdakiler, önceki örneğe göre biraz daha karmaşıktır, bash'ın ayrıştırma sırasına ve özelliklerine daha fazla dayanmaktadır. eval
Çizgi kabaca aşağıdaki sıraya göre içten çözümlenir alacağı (Aşağıdaki ifadeler sadece deyim nihai sonuca varmak için dahili olarak aşamalara ayrılmış olacaktı göstermek için denemek için, yalancı kod değil, gerçek kod unutmayın) .
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
Varsayılan ayrıştırma sırası, değerlendirmenin ne yaptığını açıklamıyorsa, üçüncü örnek neler olup bittiğini açıklığa kavuşturmak için ayrıştırmayı daha ayrıntılı olarak açıklayabilir.
Örnek 4:
Adları dizelerde bulunan değişkenlerin kendilerinin dize değerleri içerip içermediğini keşfedin .
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
İlk yinelemede:
varname="myvarname_a"
Bash, argümanı ayrıştırır eval
ve eval
tam zamanında bunu şu anda görür:
eval varval=\$$myvarname_a
Aşağıdaki sözde kod, bash'ın gerçek kodun yukarıdaki satırını, tarafından yürütülen son değere ulaşmak için nasıl yorumladığını göstermeye çalışır . (aşağıdaki satırlar tam bash kodu değil, açıklayıcıdır):eval
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)
Tüm ayrıştırma tamamlandığında, sonuç yürütülen şeydir ve etkisi açıktır, bu da eval
kendisi hakkında özellikle gizemli bir şey olmadığını gösterir ve karmaşıklık argümanının ayrıştırılmasındadır .
varval="User-provided"
Yukarıdaki örnekte kalan kod, $ varval'a atanan değerin boş olup olmadığını sınamak için yeterlidir ve öyleyse kullanıcıdan bir değer vermesini ister.
$($n)
çalışır$n
.1
Mevcut olmayan komutu çalıştırmayı dener .