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)