Linux ile BASH Script Temelleri
Bu yazıda, temel Linux gezinme ve komut bilginizin olduğu farz edilmiştir. Temel bilgilerinizi birleştirerek Script yazmayı göreceğiz. Script yazma konusu gerçekte çok detaylı olduğundan, burada genel hatlarıyla ele alınacaktır. Bash Script konusunda daha ayrıntılı bilgi için diğer kaynaklara da bakmanızı tavsiye ediyoruz.
Bu konuda anlatılanların bir kısmını ilk defa görüyorsanız endişe etmeyin. Sitemizdeki ilgili diğer yazılara bakarak o konuları da kolaylıkla inceleyebilirsiniz.
***Bash Script*** , bilgisayar terimleri açısından bakıldığında Bash Senaryosu anlamına gelmektedir. Bir başka ifade ile, Shell ortamında meydana gelebilecek ihtimallere göre senaryolar yazarak, mümkün olan tüm durumları karşılayan program geliştirmektir. Tiyatroda senaryo, oyuncular tarafından sahnelenirken, burada bilgisayar tarafından sahnelenmektedir. Bir A durumu meydana geldiğinde ekrana şunu yaz. Bir B durumu meydana geldiğinde dosyayı kopyala vb. işlemlerin hepsinin bir dosya içerisinde Script (Senaryo) olarak toplanmasına Bash Scripting denilmektedir.
Bash script sayesinde, sık sık karşılaşılan durumlar için kullanıcı müdahalesine gerek kalmadan işlemlerin otomatikleştirilmesi sağlanabilir. Her gün belli zamanlarda sisteminizin tüm dosyalarının kontrol edilerek içlerinden sadece bir önceki güne göre değişenlerin yedeğini alan bir program yazılabilir. Bu tür işlemleri her gün kullanıcı manuel olarak yapabileceği gibi bir programa da yaptırabilir.
Böyle bir programı C, Python vb. Programlama dillerini kullanarak yazabilirsiniz. Bu durumda yazdığınız program, çalışmak için bir derleyiciye ihtiyaç duyacaktır. Bir script de aynı şekilde çalışmak için bir derleyiciye ihtiyaç duyar (bash shell). Biz örneklerimizde Bourne Again Shell (bash) kullanıyoruz.
Bir komut, shell içerisinde çalışıyorsa onu Script içerisine de yerleştirebilirsiniz.
Bir komut Script içerisine yerleştirilebiliyorsa, komut satırında da çalışıyor olmalıdır.
Burada ifade edilen kuralı şöyle uyguluyoruz. Script yazarken, parçaların çalışıp çalışmadığını komut satırında test edebilirsiniz. Aldığınız test sonucu doğruysa, Script içerisine ekleyebilirsiniz.
Bash Script, esasen düz metin satırlarından oluşan bir dosyadır. İstediğiniz bir metin editörü kullanarak yazabilirsiniz. Nano, vi veya emacs bunlardan bir kaçıdır.
Basit Bir Örnek
Basit bir örnek yardımıyla konuya giriş yapıyoruz. Aşağıda bulunan dosya içeriğini kopyalayıp bir editör yardımıyla myscript.sh olarak kaydedelim..
#!/bin/bash
# Basit bir Bash Script
# Umut 10/05/2016
echo İşte sizin Ev klasörünüzdeki dosyalar:
ls ~
Kaydettiğimiz dosyanın özelliğini executable (x) olarak değiştirmemiz gerekmektedir. Komut satırından ***chmod +x myscript.sh*** komutunu kullanabilir, Görsel Arayüz (GUI) içerisinde ise dosya yöneticisinde dosyaya sağ tıklayıp çalıştırılabilir hale getirebilirsiniz.
chmod +x myscript.sh
ls -l myscript.sh
-rwxr-xr-x 1 umut umut 112 May 10 21:12 myscript.sh
Yukarıdaki komut ile yetki kontrolü yaptık. Şimdi de aşağıdaki komutla Script dosyamızı çalıştıralım. Burada dosyanın başına ./ yazıldığına dikkat edin. Bu konuyu aşağıda ayrı bir başlıkta açıkladık.
./myscript.sh ---ÇIKTI--- İşte sizin Ev klasöründeki dosyalar: Downloads Pictures Templates Dropbox test.txt
***Script Kodlarının Açıklaması*** :
#!/bin/bash # Basit bir Bash Script # Umut 10/05/2016 echo İşte sizin Ev klasörünüzdeki dosyalar: ls ~
***.*** ***sh uzantısı***
Linux, çalışma esnasında dosya uzantılarına ihtiyaç duymayan bir İşletim sistemidir. Dosya uzantıları, kullanıcıların dosyaları daha hızlı algılaması için kullanılırlar ancak zorunlu değillerdir. myscript dosyamızın uzantısı .sh olmak zorunda olmadığı halde .sh ifadesi onun bir bash script dosyası olduğunu hemen anlamamıza yardımcı olmaktadır.
#!/bin/bash
***#!:*** Bir script dosyasının ilk satırı bu iki karakterle başlamalıdır. ***Shebang *** olarak ifade edilen bu karakterlerden hemen sonra, boşluk bırakmadan hangi bash programı kullanılacaksa o programın mutlak adresi yazılır.
***/bin/bash:*** Burada belirtilmesi gereken diğer bir konu da sisteminizde hangi bash yazılımını kullandığınızdır. which bash komutunun sonucu size mutlak adresi söyleyecektir. #! ifadesinden sonra herhangi bir bash adresi yazmasanız da Script çalışabilir. Fakat sizin yazdığınız Script başka bir sistemde çalıştırılmak istendiğinde hata verme ihtimali vardır. Bu sebeple bash adresini yazmayı alışkanlık haline getirmek daha sağlıklı olacaktır.
# Basit bir Bash Script
# ifadesiyle başlayan satırlar yorum satırlarıdır. Bu satırları Bash yorum olarak farz edecek ve işleme almayacaktır. Dosyanın sahibi, oluşturulma tarihi ve oluşturulma maksadı vb. bilgilere burada yer verebilirsiniz.
Kodlarınız ve satırlar çoğaldıkça, hangi kodların ne işe yaradığını tekrar hatırlamak zorlaşacaktır. Aynı zamanda kodlarınızı bir başkasının incelemesi gerektiğinde, yorum bölümleri oldukça önem kazanır. Kodlarınızın yanına kısa yorumlar ve açıklamalar eklemeyi alışkanlık haline getirmek oldukça önemlidir. Her satıra gerek olmasa da kodlarınızın önemli bölümlerine yorum ve açıklamalar yazmanızı tavsiye ediyoruz.
echo İşte sizin Ev klasörünüzdeki dosyalar
Burada, echo komutu ile bir mesajı ekrana yazdırıyoruz. Bu örnekte sabit bir metin kullandık ancak ilerleyen bölümlerde değişkenlerin ve diğer değerlerin ekrana yazdırılması için sık sık echo komutunu kullanacağız.
ls ~
Son satırımızda ls komutu ile Ev klasörünün listesini ekrana yazdırıyoruz.
Yukarıdaki örnek Script kavramının açıklanması için oluşturulmuştur. Görünürde sadece iki satır komutu çalıştırmak gibi basit bir işlevi yerine getirmiş olabilir. Script dosyalarının içeriği geliştirildikçe, çok daha karışık işlemleri nasıl basitleştirdiklerini aşağıda göreceğiz.
Neden ./ ?
Linux komut satırına bir program yazdığınızda, sisteminiz o programı PATH adı verilen değişkende tutulan klasörlerde arayacaktır. Sizin oluşturduğunuz myscript.sh dosyası, muhtemelen bu klasörlerin içerisinde bir yerde değildir çünkü Linux güvenlik açısından kullanıcının erişebileceği klasör yetkilerini sınırlar.
Linux sisteminizin, yazdığınız komutu hangi klasörlerde aradığını echo $PATH komutu ile öğrenebilirsiniz. myscript.sh dosyanız bu klasörlerde değil başka bir yerde kayıtlıdır. Bu durumda Linux'a PATH klasörlerinde arama, şu an bulunduğum klasördeki myscript.sh programını çalıştır diye belirtmeniz gereklidir. İşte şu an bulunduğum klasör ifadesi ./ işaretiyle gerçekleştirilir.
İsterseniz PATH değişkenine klasör ilave edebilirsiniz ancak bu güvenlik açısından her zaman iyi olmayabilir. Yazdığınız Script içerisinde bağıl adresleme (./) kullanarak kod yazmak, başka kullanıcıların da bu scripti kullanabilmesine imkan verir.
Değişkenler
Değişkenler hafızalarında değerler tutan, referans olarak kullanılan ve gerektiğinde değişebilen kullanımlardır. Hafızada bir miktar yer ayırıp içerisinde bir değer tutarsınız ve ihtiyacınız olduğunda başka bir hafıza alanı kullanmadan değişkenin değerini değiştirip tekrar kullanabilirsiniz. Çok kullanışlı bir yapı olan değişkenlerin kullanımında uyulması gereken bazı kurallar bulunmaktadır. Bu kurallara mutlaka uymalısınız.
- Bir değişken tanılarken onun ADINI yazarız ve hiç boşluk bırakmadan eşittir (=) işaretiyle devam ederiz. Eşittir işaretinden sonra da boşluk bırakmadan TEK DÜZ TIRNAK içerisinde değeri yazarız.Not : Tırnaklar içerisine bir değer değil de bir komut sonucu da yazdırılabilir ancak onu birazdan göreceğiz.
- Bir değişkene atıfta bulunup referans göstermek istediğinizde, değişken isminin başına ( $ ) işareti konulmalıdır.
Örnek:
Öncelikle degiskenornek.sh isimli bir dosya oluşturalım.
nano degiskenornek.sh
Açılan dosyaya, aşağıdaki kodları yapıştırın. Bazı sistemlerde yapıştırma Shift+Ctrl+v ile yapılır. Yapıştırma işleminden sonra Ctrl+x ile çıkış isteği yapalım ve kaydetmek istiyor musunuz? sorusuna EVET cevabı verelim.
#!/bin/bash # Basit bir değişken örneği # Umut 11/05/2016 name='Umut' echo Merhaba $name
Aşağıdaki komut yardımıyla dosyayı çalıştırılabilir yaptık ve çalıştırdık.
chmod +x degiskenornek.sh ./degiskenornek.sh ---ÇIKTI--- Merhaba Umut
***Açıklama:***
name='Umut'
name değişkenin adıdır. Atıfta bulunacağımız zaman $name olarak çağırmalıyız. Eşittir işaretinin sağ ve solunda boşluk olmadığına dikkat edin. TEK DÜZ TIRNAK içerisine de değerimiz (Umut) yazılmıştır.
echo Merhaba $name
Burada ise echo komutundan Merhaba sabit değeri ile $name değişken değerini alarak ekrana yazdırması söylenmiştir.
***ALIŞTIRMA*** : degiskenornek.sh dosyasını tekrar açıp içerisine surname değişkenini ve değerini tanımlayın. Echo komutunu
echo Merhaba $name $surname
olarak değiştirip kaydedin ve çıkın. Yazdığınız scripti tekrar çalıştırın.
Script Çalıştırdığınızda Arka Plandaki Değişkenler
Siz bir Script yazıp çalıştırdığınızda, sizin tanımladığınız değişkenlere ilave olarak sisteminiz de otomatik olarak bir takım değişkenleri hayata geçirir. Bunlardan bazılarını aşağıda açıkladık:
- $0 – Scriptin adı bu değişkende tutulur.
- $1 - $9 – Scripte komut satırından (dışarıdan gönderilen) argümanlar 1 ile 9 arasındaki değişkenlerde kayıt edilir.
- $# - Scripte dışarıdan gönderilen toplam argüman sayısı bu değişkende tutulur.
- $* - Scripte dışarıdan gönderilen argümanların tamamı anlamına gelir.
***Örnek*** :
Yukarıdaki örnekte yaptığımıza benzer şekilde aşağıdaki nano komutuyla bir dosya oluşturalım.
nano otomatikornek.sh
Açılan dosyaya, aşağıdaki Script kodlarını yapıştıralım.
#!/bin/bash # Basitin biraz ötesinde değişken örneği # Umut 11/05/2016 clear echo Ben: Benim adım $0 ve ben komut satırından toplam $# argüman gönderdim. echo Bilgisayar: Evet, gönderdikleriniz bunlardı: $* echo Bilgisayar: Ve gönderdiğiniz 2. argüman da $2, doğru mu? :\)
Dosyayı çalıştırılabilir yapalım ve çalıştıralım.
chmod +x otomatikornek.sh ./otomatikornek.sh Umut Serhat Mesut ---ÇIKTI--- Benim adım ./otomatikornek.sh ve ben komut satırından toplam 3 argüman gönderdim. Bilgisayar: Evet, gönderdikleriniz bunlardı: Umut Serhat Mesut Bilgisayar: Ve gönderdiğiniz 2. argüman da Serhat , doğru mu? :)
***Açıklama:***
echo Ben: Benim adım $0 ve ben komut satırından toplam $# argüman gönderdim.
Bu satırda $0 ile script dosyasının ismi çağrılmış ve $# ile toplam argüman sayısı kullanılmıştır.
echo Bilgisayar: Evet, gönderdikleriniz bunlardı: $*
Bu satırda $* ile değişkenlerin tamamı yazdırılmıştır.
echo Bilgisayar: Ve gönderdiğiniz 2. argüman da $2, doğru mu? :\)
Bu satırda $2 ile gönderilen 2.sıradaki argüman değişkeni çağrılmış ve ekrana yazdırılmıştır.
***ALIŞTIRMA*** :
Scripte 1 argüman gönderseydik ne olurdu?
Scriptte :\) yazdığımız halde çıktıda neden : ) olarak görünüyor?
Ters Tırnaklar
Yukarıdaki örneklerde değişkenlerimizi TEK DÜZ TIRNAK içerisinde sabit string değerler olarak tanımladık. Bazen bir değişkene, bir komutun sonucunu kaydetmek isteyebiliriz. Bu durumda sabit değil bir komutu tanımlamamız gerekecektir. Böyle durumlarda değişkenin eşittir işaretinin sağ tarafında bulunan ifadeyi TERS TIRNAK (`ifade`) içerisinde yazmamız gerekecektir. Klavyelerimizde yeri pek bilinmeyen bu işaret genellikle , ve ; tuşunda (TR Q) bulunur. AltGr tuşuyla birlikte virgül karakterinin bulunduğu tuşa basarak yazabilirsiniz. Bununla ilgili bir örnek yapalım.
Örnek:
Bu komut ile terstirnak.sh dosyasını nano editörde oluşturalım.
nano terstirnak.sh
Aşağıdaki script kodlarını terstirnak.sh dosyası içerisine yapıştıralım ve Ctrl+x ile çıkış isteği yapalım.
#!/bin/bash # Basit bir TERS TIRNAK içinde değişken örneği # Umut 11/05/2016 sistem=`uname -a` echo Sistem bilginiz: $sistem
terstirnak.sh dosyasını çalışır hale getirelim ve çalıştıralım.
chmod +x terstirnak.sh ./terstirnak.sh ---ÇIKTI--- Sistem bilginiz: Linux umut-X550JX 4.4.0-21-generic #37~14.04.1-Ubuntu SMP Wed Apr 20 16:33:38 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
***Açıklama*** :
sistem=`uname -a`
uname -a bir komuttur. Echo ekrana Ters Tırnaklar içerisindeki ifadeyi aynen değil, komutun sonucunu yazdırmıştır.
***ALIŞTIRMA*** :
Script dosyasındaki sistem değişkenine başka komutlar yazarak sonuçları gözlemleyin.
Basit Bir Yedekleme Script Dosyası
Aşağıda, ismini verdiğiniz bir klasörü, yedeklerinizin bulunduğu bir diğer klasöre yedekleme yapan Script verilmiştir. İsterseniz ayrı bir .sh dosyası oluşturarak deneyebilirsiniz. İsterseniz de kodlar üzerinden hangi işlemlerin yapıldığını takip edebilirsiniz. Şu ana kadar anlatılanların pekişmesi açısından üzerinde çalışmanızı tavsiye ediyoruz.
Script, Sisteminize bir zarar meydana getirmemesi için oluşturacağı klasör ve dosyaları /tmp klasörüne kaydedecektir.
nano backup.sh
#!/bin/bash # Bir yedekleme örneği # Umut 11/05/2016 clear date=`date +%F` mkdir /tmp/$1&&touch /tmp/$1/dosya1.txt /tmp/$1/dosya2.txt echo /tmp Klasörüne $1 Klasörü ve içeriği oluşturuldu. sleep 5 mkdir -p /tmp/backups/$1_$date echo /tmp Klasörüne /backup klasörü ve $1_$date Klasörü oluşturuldu. sleep 5 cp -R /tmp/$1 /tmp/backups/$1_$date echo /tmp klasöründe bulunan $1 klasör içeriği /tmp/backups/$1_$date klasörüne yedeklendi. sleep 5 echo Yedekleme tamamlandı. echo isterseniz /tmp/$1 klasörünü ve echo /tmp/backups/$1_$date klasörünü silebilirsiniz. echo /tmp klasörü sisteminizi kapattığınızda kendisi zaten silinir. sleep 1 echo ESAS KLASÖR İÇERİĞİ ls -l /tmp/$1 sleep 1 echo YEDEKLENEN KLASÖR İÇERİĞİ ls -l /tmp/backups/$1_$date/$1/ echo Script sona erdi…
chmod +x backup.sh ./backup.sh yedekleme
If -Then-Else Kullanımı
Yukarıdaki yedekleme örneğinde işlemlerin hatasız yapıldığı farz edilmiştir. Yapılan işlemlerin herhangi bir adımında sorun çıkması durumda ne yapılacağı senaryoda yoktur. Bu tür durumlar için Script yazarken kullanılan şart ve durumsal yapılardan bir tanesi If yapısıdır.
If yapısı, bir şartı kontrol eder ve o şart sağlanıyorsa işlemi yapar. Sağlanmıyorsa işlemi iptal eder. Bir nevi ön kontrol yapar. Kontrol, işlem gerçekleşmeden önce yapılmaktadır.
Aşağıdaki örneği, önceki örneklerde olduğu gibi bir .sh dosyası oluşturup kaydedebilir veya kodlar üzerinden de inceleyerek anlamaya çalışabilirsiniz.
#!/bin/bash # Bir yedekleme örneği # Umut 11/05/2016 if [ $# != 1 ] then clear echo Kullanım: Yedeklenecek klasörü belirten 1 tek klasör adı girmelisiniz. exit fi if [ ! -d /tmp/$1 ] then clear echo 'Adını verdiğiniz klasör bulunmuyor. Yeni klasör ve içeriği oluşturulacak' mkdir /tmp/$1&&touch /tmp/$1/dosya1.txt /tmp/$1/dosya2.txt echo /tmp Klasörüne $1 Klasörü ve içeriği oluşturuldu. sleep 5 fi echo --------------------------- date=`date +%F` # Bugün yedeği alınmış başka bir klasör var mı diye bakıyoruz? if [ -d /tmp/backups/$1_$date ] then echo 'Bu klasörün bugün yedeği alınmış. Yine de üstüne yazılsın mı?' read answer if [ $answer != 'y' ] then exit fi else mkdir -p /tmp/backups/$1_$date echo /tmp Klasörüne /backup klasörü ve $1_$date Klasörü oluşturuldu. sleep 5 fi cp -R /tmp/$1 /tmp/backups/$1_$date echo /tmp klasöründe bulunan $1 klasör içeriği /tmp/backups/$1_$date klasörüne yedeklendi. sleep 5 echo Yedekleme tamamlandı. echo isterseniz /tmp/$1 klasörünü ve echo /tmp/backups/$1_$date klasörünü silebilirsiniz. echo /tmp klasörü sisteminizi kapattığınızda kendisi zaten silinir. sleep 1 echo ESAS KLASÖR İÇERİĞİ ls -l /tmp/$1 sleep 1 echo YEDEKLENEN KLASÖR İÇERİĞİ ls -l /tmp/backups/$1_$date/$1/ echo Script sona erdi…
***Açıklama*** :
1.Kullanım:
if şart=eşleşiyor then işlemleri yap exit fi
Yukarıdaki örnekte ilk if kullanımı [ $# != 1 ] şartı ile kontrol yapmaktadır. Bu şart, Scripte dışarıdan girilen argüman sayısının bire eşit olmaması durumudur. Öyleyse burada Script'e girilen argüman bire eşit değilse yani (0 veya Birden fazla argüman girildiyse) bir takım işlemleri yapıp çıkması istenmiştir.
2.Kullanım:
if şart1=eşleşiyor then işlemleri yap if şart2=eşleşiyor then işlemleri yap exit fi else şart1 gerçekleşmediğinde bu işlemleri yap exit fi:
Yukarıdaki örnek içerisinde 2.kullanım şekli de if yapısını ELSE yani diğer türlü olduğunda yapılacak işlemleri de tanımlayarak algoritmayı genişleterek kullandık. Üstelik şart1 gerçekleştiğinde yapılacak işlemler arasına da bir if kullanımı yerleştirerek içiçe kullanımı da göstermiş olduk. Bu tarz kullanımda if kontrol mekanizmasına [-d /tmp/backups/$1_$date ] şartı ile yedeğin bugün içerisinde önceden alınıp alınmadığı kontrol ettiriliyor. Alınmışsa takip edilecek yol ve işlemler belirtiliyor. Alınmamış ise (ELSE) yapılacak işlemler belirtiliyor.
3.Kullanım:
echo 'Bu klasörün bugün yedeği alınmış. Yine de üstüne yazılsın mı?' read answer if [ $answer != 'y' ] then exit
Burada ise, kullanıcıya bir soru soruluyor ve cevabı bekleniyor. Girilen cevap ***read answer*** komutu ile answer değişkenine yerleştiriliyor, sonrasında if-then yapısıyla kontrol ediliyor. Girilen cevap y değilse ***[!='y']*** çıkılıyor.
***ALIŞTIRMA*** : Kullanıcı cevap olarak y tuşuna basması gerektiğini nereden bilecek?