Linux Bash Komut Dosyalarında eval Nasıl Kullanılır
Yayınlanan: 2022-08-22
Tüm Bash komutları arasında, zavallı eski eval muhtemelen en kötü itibara sahiptir. Haklı mı yoksa sadece kötü basın mı? Bu en az sevilen Linux komutlarının kullanımını ve tehlikelerini tartışıyoruz.
Eval Hakkında Konuşmalıyız
eval kullanıldığında, değerlendirme öngörülemeyen davranışlara ve hatta sistem güvensizliklerine yol açabilir. Seslerine bakılırsa muhtemelen kullanmamalıyız, değil mi? Pek iyi değil.
Otomobiller için de benzer bir şey söyleyebilirsiniz. Yanlış ellerde, ölümcül bir silahtırlar. İnsanlar onları baskınlarda ve kaçış araçları olarak kullanıyor. Hepimiz araba kullanmayı bırakmalı mıyız? Hayır tabii değil. Ancak doğru şekilde ve onları sürmeyi bilen kişiler tarafından kullanılmaları gerekir.
eval için kullanılan genel sıfat “kötülük”tür. Ama her şey nasıl kullanıldığına bağlı. eval komutu, bir veya daha fazla değişkenden gelen değerleri toplar. Bir komut dizisi oluşturur. Daha sonra bu komutu yürütür. Bu, komut dosyanızın yürütülmesi sırasında bir komutun içeriğinin dinamik olarak türetildiği durumlarla başa çıkmanız gerektiğinde kullanışlı hale getirir.
Bir komut dosyası, komut dosyasının dışında bir yerden alınan bir dizede eval kullanmak üzere yazıldığında sorunlar ortaya çıkar. Bir kullanıcı tarafından yazılabilir, bir API aracılığıyla gönderilebilir, bir HTTPS isteğine etiketlenebilir veya komut dosyasının dışında herhangi bir yerde olabilir.
eval üzerinde çalışacağı dize yerel ve programlı olarak türetilmediyse, dizenin gömülü kötü niyetli yönergeler veya diğer hatalı biçimlendirilmiş girdiler içerme riski vardır. Açıkçası, eval kötü amaçlı komutları yürütmesini istemezsiniz. Güvende olmak için, harici olarak oluşturulmuş dizeler veya kullanıcı girişi ile eval kullanmayın.
Eval ile İlk Adımlar
eval komutu, yerleşik bir Bash kabuk komutudur. Bash varsa, eval mevcut olacaktır.
eval , parametrelerini tek bir dizede birleştirir. Birleştirilmiş öğeleri ayırmak için tek bir boşluk kullanır. Argümanları değerlendirir ve ardından tüm dizeyi yürütülecek kabuğa iletir.
Şimdi wordcount adında bir değişken oluşturalım.
wordcount="wc -w raw-notes.md"
Dize değişkeni, "raw-notes.md" adlı bir dosyadaki sözcükleri saymak için bir komut içerir.
Bu komutu, değişkenin değerini ileterek yürütmek için eval kullanabiliriz.
eval " $wordcount " 
Komut, bir alt kabukta değil, geçerli kabukta yürütülür. Bunu kolayca gösterebiliriz. “variables.txt” adında kısa bir metin dosyamız var. Bu iki satırı içerir.
first=Nasıl Yapılır ikinci = Geek
Bu satırları terminal penceresine göndermek için cat kullanacağız. Ardından, metin dosyasının içindeki talimatların yerine getirilmesi için bir cat komutunu değerlendirmek için eval kullanacağız. Bu bizim için değişkenleri ayarlayacaktır.
kedi değişkenleri.txt değerlendirme "$(kedi değişkenleri.txt)" echo $ilk $saniye

Değişkenlerin değerlerini yazdırmak için echo kullanarak, eval komutunun bir alt kabukta değil, geçerli kabukta çalıştığını görebiliriz.
Alt kabuktaki bir işlem, üst öğenin kabuk ortamını değiştiremez. eval geçerli kabukta çalıştığından, eval tarafından ayarlanan değişkenler, eval komutunu başlatan kabuktan kullanılabilir.
Bir komut dosyasında eval kullanırsanız, eval tarafından değiştirilecek kabuğun, onu başlatan kabuk değil, komut dosyasının içinde çalıştığı alt kabuk olduğunu unutmayın.
İLGİLİ: Linux cat ve tac Komutları Nasıl Kullanılır
Komut Dizisinde Değişkenleri Kullanma
Komut dizelerine diğer değişkenleri dahil edebiliriz. Tamsayıları tutmak için iki değişken ayarlayacağız.
sayı1=10 sayı2=7
İki sayının toplamını döndürecek bir expr komutunu tutacak bir değişken oluşturacağız. Bu, komuttaki iki tamsayı değişkeninin değerlerine erişmemiz gerektiği anlamına gelir. expr ifadesinin etrafındaki geri dönüşlere dikkat edin.
add="`expr $sayı1 + $sayı2`"
Bize expr ifadesinin sonucunu göstermek için başka bir komut oluşturacağız.
göster="eko"
echo dizesinin sonuna veya expr dizesinin başına bir boşluk eklememiz gerekmediğine dikkat edin. eval bununla ilgilenir.
Ve kullandığımız tüm komutu yürütmek için:
değerlendirme $göster $ekle

expr dizesindeki değişken değerleri, yürütülecek kabuğa iletilmeden önce eval tarafından dizeye değiştirilir.
İLGİLİ: Bash'de Değişkenlerle Nasıl Çalışılır
Değişkenlerin İçindeki Değişkenlere Erişme
Bir değişkene bir değer atayabilir ve ardından o değişkenin adını başka bir değişkene atayabilirsiniz. eval kullanarak, ikinci değişkende saklanan değer olan adından birinci değişkende tutulan değere erişebilirsiniz. Bir örnek bunu çözmenize yardımcı olacaktır.
Bu komut dosyasını bir düzenleyiciye kopyalayın ve "assign.sh" adlı bir dosya olarak kaydedin.
#!/bin/bash
title="Nasıl Yapılır Meraklısı"
web sayfası=başlık
komut = "eko"
eval $command \${$web sayfası} chmod komutu ile çalıştırılabilir hale getirmemiz gerekiyor.
chmod +x atama.sh


Bu makaleden kopyaladığınız tüm komut dosyaları için bunu yapmanız gerekir. Her durumda uygun komut dosyası adını kullanın.
Komut dosyamızı çalıştırdığımızda, eval komutu webpage değişkenini kullanıyor olsa da, title değişkenindeki metni görüyoruz.
./atama.sh

Kaçan dolar işareti “ $ ” ve kaşlı ayraçlar “ {} ”, eval'in adı webpage değişkeninde saklanan değişkenin içinde tutulan değere bakmasına neden olur.
Dinamik Olarak Oluşturulmuş Değişkenleri Kullanma
Değişkenleri dinamik olarak oluşturmak için eval kullanabiliriz. Bu komut dosyası "loop.sh" olarak adlandırılır.
#!/bin/bash
toplam=0
label="Döngü tamamlandı. Toplam:"
{1..10} içindeki n için
yapmak
değerlendir x$n=$n
echo "Döngü" $x$n
((toplam+=$x$n))
tamamlamak
echo $x1 $x2 $x3 $x4 $x5 $x6 $x7 $x8 $x9 $x10
echo $etiket $toplam Oluşturduğumuz değişkenlerin değerlerinin toplamını tutan total adında bir değişken oluşturur. Daha sonra label adında bir dize değişkeni oluşturur. Bu basit bir metin dizisidir.
10 kez döngü yapacağız ve x10 x1 kadar 10 değişken oluşturacağız. Döngünün gövdesindeki eval ifadesi “x”i sağlar ve değişken adını oluşturmak için $n döngü sayacının değerini alır. Aynı zamanda, yeni değişkeni $n döngü sayacının değerine ayarlar.
Yeni değişkeni terminal penceresine yazdırır ve ardından total değişkeni yeni değişkenin değeriyle artırır.
Döngünün dışında, 10 yeni değişken bir kez daha, hepsi bir satırda yazdırılır. Değişkenlere, adlarının hesaplanmış veya türetilmiş bir versiyonunu kullanmadan gerçek adlarıyla da başvurabileceğimizi unutmayın.
Son olarak, total değişkenin değerini yazdırıyoruz.
./loop.sh

İLGİLİ: Primer: Bash Döngüler: için, süre ve kadar
Dizilerle eval kullanma
Uzun süredir çalışan ve sizin için bazı işlemler gerçekleştiren bir komut dosyanızın olduğu bir senaryo hayal edin. Bir zaman damgasından oluşturulan bir adla bir günlük dosyasına yazar. Bazen yeni bir günlük dosyası başlatır. Script bittiğinde herhangi bir hata yoksa oluşturduğu log dosyalarını siler.
Basitçe rm *.log olmasını istemezsiniz, yalnızca oluşturduğu günlük dosyalarını silmesini istersiniz. Bu komut dosyası, bu işlevi simüle eder. Bu "clear-logs.sh".
#!/bin/bash
-a günlük dosyalarını bildir
dosya sayısı=0
rm_string="eko"
function create_logfile() {
((++dosya sayısı))
dosyaadı=$(tarih +"%Y-%m-%d_%H-%M-%S").log
günlük dosyaları[$filecount]=$dosyaadı
echo $filecount "Oluşturuldu" ${logfiles[$filecount]}
}
# betiğin gövdesi. Burada bazı işlemler yapılır.
# periyodik olarak bir günlük dosyası oluşturur. bunu simüle edeceğiz
create_logfile
uyku 3
create_logfile
uyku 3
create_logfile
uyku 3
create_logfile
# kaldırılacak dosya var mı?
için ((dosya=1; dosya<=$dosya sayısı; dosya++))
yapmak
# günlük dosyasını kaldır
eval $rm_string ${logfiles[$file]} "silindi..."
günlük dosyaları[$dosya]=""
tamamlamak Komut dosyası, logfiles adlı bir dizi bildirir. Bu, komut dosyası tarafından oluşturulan günlük dosyalarının adlarını tutacaktır. filecount adında bir değişken bildirir. Bu, oluşturulan günlük dosyalarının sayısını tutacaktır.
Ayrıca rm_string adında bir dize bildirir. Gerçek dünya komut dosyasında, bu rm komutunu içerir, ancak ilkeyi tahribatsız bir şekilde gösterebilmek için echo kullanıyoruz.
create_logfile() işlevi, her bir günlük dosyasının adlandırıldığı ve açılacağı yerdir. Yalnızca dosya adını oluşturuyoruz ve dosya sisteminde oluşturulmuş gibi davranıyoruz.
İşlev, filecount değişkenini artırır. Başlangıç değeri sıfırdır, bu nedenle oluşturduğumuz ilk dosya adı dizide birinci konumda saklanır. Bu bilerek yapılır, daha sonra bakınız.
Dosya adı, date komutu ve “.log” uzantısı kullanılarak oluşturulur. Ad, dizide filecount tarafından belirtilen konumda saklanır. Ad, terminal penceresine yazdırılır. Gerçek dünya komut dosyasında, gerçek dosyayı da yaratırsınız.
Komut dosyasının gövdesi, sleep komutu kullanılarak simüle edilir. İlk günlük dosyasını oluşturur, üç saniye bekler ve ardından bir başkasını oluşturur. Dosya adlarındaki zaman damgalarının farklı olması için aralıklı dört günlük dosyası oluşturur.
Son olarak, günlük dosyalarını silen bir döngü vardır. Döngü sayacı dosyası bire ayarlanır. Oluşturulan dosya sayısını tutan filecount değerine kadar ve buna kadar sayar.
filecount sayısı hala sıfıra ayarlanmışsa (çünkü hiçbir günlük dosyası oluşturulmamıştır), bir sıfırdan küçük veya sıfıra eşit olmadığı için döngü gövdesi hiçbir zaman yürütülmez. Bu nedenle filecount değişkeni bildirildiğinde sıfıra ayarlandı ve bu nedenle ilk dosya oluşturulmadan önce artırıldı.
Döngünün içinde, tahribatsız rm_string ve diziden alınan dosyanın adıyla eval kullanıyoruz. Ardından dizi öğesini boş bir dizeye ayarladık.
Komut dosyasını çalıştırdığımızda gördüğümüz şey budur.
./clear-logs.sh

Her Şey Kötü Değil
Çok kötü eval değerlendirme kesinlikle kullanımlarına sahiptir. Çoğu araç gibi, dikkatsizce kullanıldığında tehlikelidir ve birden fazla şekilde.
Üzerinde çalıştığı dizelerin dahili olarak oluşturulduğundan ve insanlardan, API'lerden veya HTTPS istekleri gibi şeylerden alınmadığından emin olursanız, büyük tuzaklardan kaçınırsınız.
İLGİLİ: Linux Terminalinde Tarih ve Saat Nasıl Görüntülenir (ve Bash Komut Dosyalarında Kullanılır)



