Shell Script #0 – (Giriş)

#! Shell Scripting

Not: Elimin alışık olduğu yegane shell “bash” olduğu için, bu dizide çok büyük oranda bash üzerinde çalışacağız.

Shell Nedir?

İşletim sistemini kullanabilmemizi sağlayan arayüze “kabuk (shell)” deriz. Shell’ler GUI ya da TUI olabilir. Shell denilince aklınıza yalnızca yalnızca siyah ekranda akan yazılar gelmemeli. Fakat yaygın kullanıma baktığımızda eğer bir işlem grafik arayüz üzerinde, fare kullanarak, ikonları görerek vs. yapılıyorsa kullanılan bu ortama GUI denildiğini görürüz. Grafik arayüzün olmadığı durumlarda ise kabuk, shell, terminal, konsol, seri bağlantı, CLI (Command Line Interface) gibi ifadeleri görürsünüz. Bir de “bash” denildiğini görürsünüz arkadaşlar… Shell’e bash demek; traş bıçağına jilet (Gilette), kağıt mendile Selpak demek gibi bir şeydir. Yapmayın.

Shell Script Nedir?

Shell’ler interaktif yapıdadır. Bir şey yazarsınız ve bir yanıt alırsınız. Fakat bazen bu işler bir rutin hâline gelir ve yanıtı görmek istemezsiniz. Olacaklar zaten oldukça tahmin edilebilir durumdadır. Örneğin, bir dizin içerisinde yer alan “PNG” uzantılı dosyaları silmek istiyorsunuz. Tek amacınız bu. İlgili komutu çalıştırdığınızda, bu dosyalar – varsa – silinecektir. Farklı bir senaryo düşünelim. Bir dizin içerisinde yer alan “tmp” uzantılı dosyaların her 3 saatte bir silinmesini istiyorsunuz. İşleri biraz daha ilginçleştirelim. Web server’ınıza ait logların her 24 saatte bir arşivlenmesini, sıkıştırılmasını, bu arşivin farklı bir noktaya taşınmasını ve orijinal log dosyalarının da silinmesini istiyorsunuz. Süreç hep aynı, beklentiler hep aynı, kullanılan araçlar hep aynı. Peki bunu otomatize etmenin bir yolu yok mudur?

İşte burada devreye “shell programlama (shell programming)” ya da “shell betikleri (shell scripting)” giriyor. Shell programlama biraz sıkıntılı bir kullanım aslında. Çünkü ortada bir program yok. Komutların (instruction) yer aldığı bir metin dosyası (text file) var. Bu dosya, onu yorumlayabilecek bir programa (örneğin bash) veriliyor ve komutlar işletiliyor. Shell script özünde bu, bir shell tarafından işletilecek komutların yer aldığı metin dosyası.

Shell Script’in İçeriği

Aslında shell’inize yazdığınız şeyler, shell script’inizin içeriğini oluşturur.

Bir shell script’te, ilgili shell’in yerleşik komutları yer alabilir. “echo”, “pwd” gibi. “pwd”yi görünce hemen saldırmayın. pwd bir program olduğu gibi aynı zamanda bir bash yerleşiğidir (bash internal).

“Linux komutları” diye bilinen fakat aslında “GNU/Linux programları” olan ls, cp, mv, grep gibi programlar shell script’lerinde kullanılabilir. Burada dikkat edilmesi gereken nokta, script’in yazıldığı ortamdaki programlar ve path ayarları ile; çalıştırılacağı ortamdaki programlar ve path ayarlarının tutarlı olmasıdır. Örneğin siz, birtakım dosyaları yeniden adlandırmak için “mv” programından faydalanan bri shell script yazmış olabilirsiniz. Benim cihazımda ise “mv” programının adını “degistir” yaptığımı düşünelim. Dolayısıyla sizin script’iniz benim cihazımda çalışmayacaktır. Öte yandan “mv” ismini “degistir” yaptıysam, zaten hiçbir şeyi çalıştırmayı hak etmiyorumdur artık 🙂

Tabii diğer script’lerde olduğu gibi karar yapıları (if – else gibi), döngüler (for, while gibi) karşımıza çıkacak. Değişkenler oluşturulacak, matematiksel işlemler yapılacak.

GNU Bash

GNU Bash’e geçmeden önce, Bourne Shell’den (sh)^1 bahsedelim. Bourne Shell, işletim sistemlerinde kullanılması için yazılmış bir komut satırı arayüzüdür (CLI). 1976’da çalışmaları başlamış ve 1979’da Version 7 Unix’te kullanılmaya başlanmıştır. Stephen Bourne tarafından geliştirilmiştir.

GNU Bash (Bourne-Again SHell)^2 ise, sh ile uyumlu yeni bir shell’dir. GNU projesi kapsamında geliştirilmiştir. Komut satırında düzenleme, sınırsız komut geçmişi, 2’den 64’e tüm tabanlarda matematiksel işlemler gibi yenilikler getirmiştir.

GNU Bash, birçok GNU/Linux dağıtımında varsayılan shell olarak karşımıza çıkmaktadır.

İlk Scriptimiz

Shell script’leri, bir metin dosyasıdır demiştik. Yapmamız gereken şey, bir metin dosyasına gerekli komutları yazdıktan sonra bunu kaydetmek ve çalıştırmak. Script dillerine baktığımızda, bir yorumlayıcıya ihtiyaç duyduğunu görürüz. Örneğin, bir JavaScript dosyasını çalıştırmak için web tarayıcılarına ihtiyaç duyarız. Bir Python script’ini çalıştırmak için de “python test.py” gibi bir komut çalıştırırız. Benzer işi, shell script’imiz için de yapacağız.

Script’in Oluşturulması

Bash ortamında ekrana bir mesaj yazdırmak için “echo” komutunu kullanırız.

[root@localhost ~]# echo Shell scripting öğreniyoruz
Shell scripting öğreniyoruz

Şimdi dümdüz bir anlatım yapıyor olsak, “Arkadaşlar metinleri tek tırnak ya da çift tırnak içine alabilirsiniz.” derdik. Ama demiyoruz. Çünkü bu iş her zaman böyle çalışmıyor, gerçekten. Bu yüzden deniyoruz, bu yüzden test ediyoruz, bu yüzden bir şeyleri daha derinlemesine öğrenmeye çalışıyoruz. Aşağıdaki çıktıyı inceleyiniz:

[root@localhost ~]# echo Shell scripting öğreniyoruz
Shell scripting öğreniyoruz
[root@localhost ~]# echo 'Shell scripting öğreniyoruz'
Shell scripting öğreniyoruz
[root@localhost ~]# echo "Shell scripting öğreniyoruz"
Shell scripting öğreniyoruz
[root@localhost ~]# echo 'Shell scripting öğreniyoruz!'
Shell scripting öğreniyoruz!
[root@localhost ~]# echo "Shell scripting öğreniyoruz!"
-bash: !": event not found

echo’yu hiçbir işaret olmadan kullandık. Sorun çıkmadı. Tek tırnak ve çift tırnakla da kullandık. Yine sorun çıkmadı. Cümlemizin sonuna ünlem işareti ekledik. Tek tırnaklarda sorun çıkmadı fakat çift tırnak patladı 🙂 Peki neden?

Bash'te echo çıktıları.
Bash’te echo çıktıları.

Yukarıdaki çıktıyı inceleyelim şimdi. Tırnak işaretleri olmadan ve tek tırnak işaretleriyle “Shell script!” yazabiliyoruz. Ünlem işareti de var. Fakat çift tırnakla yazamadık. Aldığımız hataya bakın, “event not found”. Yani, böyle bir olay bulunamadı. Olay derken? “!” işareti, bash’te – ve aslında farklı shell’lerde de – “geçmiş (history)” anlamında kullanılıyor. Ünlem işareti sonrasında yazdığınız karakterler ile başlayan en son komutu çalıştırırsınız.

Yukarıdaki örneğe tekrar baktığımızda şunu görüyoruz. Başarılı olarak çalışan son komut, tek tırnak işaretleri içinde yazılmış mesaj, 3. satırda. 5. satırdaki çift tırnaklı örnek hata vermiş. 7. satırda ise “!ec” kullandık. Yani, “ec ile başlamış en son başarılı komutu çalıştır” dedik. !ec sonrasında ise “ec ile başlamış en son başarılı komutun” ne olduğu gösterilmiş ve çalıştırılmıştır. Ünlem işareti, kendinden sonra gelen karakterle başlayan bir şeyi çalıştırmak istediği için ve bu karakteri de çift tırnak olarak verdiğimiz için başarılı olamadı, hata verdi. Görüldüğü üzere, tek tırnak işaretinde böyle bir sorun yaşamamıştık.

Şimdi, alt alta bazı mesajlar yazacak bir bash script hazırlayalım:

[root@localhost bashscript]# vi echo_ornegi.sh
[root@localhost bashscript]# cat echo_ornegi.sh
echo Alti üstü beş metreydi
echo dertlerinin birikimi
echo Belki biter dedin ama
echo sen kaparsan gözlerini
[root@localhost bashscript]#

“echo”nun mesaj yazdıracağını biliyoruz. Bir text editör (bu örnekte vi) kullanarak “echo_ornegi.sh” isminde bir dosya oluşturdum. İçine yazdıklarımı da “cat” komutuyla gösterdim. Bakalım çalıştırınca ne olacak?

[root@localhost bashscript]# bash echo_ornegi.sh
Alti üstü beş metreydi
dertlerinin birikimi
Belki biter dedin ama
sen kaparsan gözlerini
[root@localhost bashscript]#

Gördüğünüz gibi, yazmış olduğum script dosyasını, bash programına parametre olarak gönderdim ve başarıyla çalıştı.

[root@localhost bashscript]# bash echo_ornegi.sh
Alti üstü beş metreydi
dertlerinin birikimi
Belki biter dedin ama
sen kaparsan gözlerini
[root@localhost bashscript]# ls -l echo_ornegi.sh
-rw-r--r--. 1 root root 113 Eki 28 14:53 echo_ornegi.sh
[root@localhost bashscript]# echo_ornegi.sh
-bash: echo_ornegi.sh: komut yok
[root@localhost bashscript]# ./echo_ornegi.sh
-bash: ./echo_ornegi.sh: Erişim engellendi
[root@localhost bashscript]# file echo_ornegi.sh
echo_ornegi.sh: UTF-8 Unicode text
[root@localhost bashscript]#

Yukarıdaki çıktıyı adım adım inceleyelim:

  1. bash echo_ornegi.sh ile scripti çalıştırdık. Sorun görünmedi.
  2. ls -l ile bu script’in izinlerine baktık. Gördük ki, sahibinin yalnızca “rw” yani “okuma – yazma” izinleri var. Bu bilgi cepte dursun.
  3. echo_ornegi.sh scriptini çalıştırmak istedim. Çalışmadı. “Komut yok” hatası aldık. Çünkü script’in olduğu yer, PATH değişkenimizde tanımlı değil.
  4. ./echo_ornegi.sh ile, “PATH’e bakmana gerek yok, bulunduğum yerdeki echo_ornegi.sh dosyasını çalıştır.” dedik. “Erişim engellendi” hatası aldık. Hatırlarsanız bu dosya için okuma – yazma iznimiz vardı, fakat çalıştırma (x) iznimiz yoktu.
  5. file ile, bu dosyanın tipine baktık. “UTF-8 Unicode text” olduğunu gördük.

Bu durumda dosyamıza “çalıştırma” izni vereceğiz. Ayrıca, her çalıştırma sırasında başına “bash” eklemek zorunda kalmamak için, bu dosyanın bir “bash script’i” olduğunu anlatacak bir satır ekleyeceğiz. Bu satıra, “shebang^3 diyoruz.

[root@localhost bashscript]# vi echo_ornegi.sh
[root@localhost bashscript]# cat echo_ornegi.sh
#! /bin/bash
echo Alti üstü beş metreydi
echo dertlerinin birikimi
echo Belki biter dedin ama
echo sen kaparsan gözlerini
[root@localhost bashscript]# file echo_ornegi.sh
echo_ornegi.sh: Bourne-Again shell script, UTF-8 Unicode text executable
[root@localhost bashscript]# chmod u+x echo_ornegi.sh
[root@localhost bashscript]# ./echo_ornegi.sh
Alti üstü beş metreydi
dertlerinin birikimi
Belki biter dedin ama
sen kaparsan gözlerini
[root@localhost bashscript]#

Neler yaptığımıza bakalım:

  1. vi ile dosyayı açtık. Shebang’i ekledik.
  2. cat ile içeriğini okuduk, ekranda görüyoruz. Eklediğimiz shebang satırı, “#! /bin/bash“. Shebang’ler “#!” ile başlar. Devamında ise hangi shell ile çalıştıracağımızı belirtmek için shell’in full path’ini verdik, “/bin/bash”.
  3. file ile kontrol ettik. Daha önce baktığımızda “UTF-8 text” görünen dosya, artık “Bourne-Again shell script. UTF-8 Unicode text executable.” oldu.
  4. chmod u+x ile bu dosyanın sahibine çalıştırma yetkisi verdik.
  5. ./echo_ornegi.sh ile çalıştırdık. Sorun yaşanmadı.
[root@localhost bashscript]# sh echo_ornegi.sh
Alti üstü beş metreydi
dertlerinin birikimi
Belki biter dedin ama
sen kaparsan gözlerini
[root@localhost bashscript]#

Aynı script’i “sh” ile çalıştırdığımızda da bir sorun çıkmadığını görüyoruz. Yazdığımız bu script, sh ile uyumlu bir script’ti. GNU Bash’in zaten sh ile uyumlu olduğunu söylemiştik. Tabii bu bilgi ve bu örnek ışığında, “Her türlü bash script kesinlikle her zaman sh üzerinde de çalışacaktır.” gibi bir sonuca varmamalıyız.

Sonuç Olarak

Görüldüğü üzere, eğer shell scripting ile uğraşacaksanız bazı konulara hakim olmanız gerekiyor:

  • Full path, relative path
  • Shell komutları
  • Temel GNU/Linux araçları
  • Dosya ve dizin izinleri

Ek olarak, yukarıdaki örneklerde bütün script’leri “root” kullancısıyla yazdığımı ve çalıştırdığımı görüyorsunuz. Kaynağını bilmediğiniz bir script’i root yetkileriyle çalıştırmak, bütün mal varlığınızı rastgele birinin üzerine geçirmek gibidir. Kendi script’lerinizi yazarken eğer ne yaptığınızdan %100 emin değilseniz, lütfen root yerine standart yetkilere sahip bir kullanıcı ile yazın ve çalıştırın. Gördüğünüz her script’i çalıştırmaktan kaçının. Doğru ve güvenilir kaynaktan geldiğini teyit edemediğiniz script’lerden uzak durun. Ve son olarak, eğer root yetkileri ile çalıştırılacak bir script yazıyorsanız; hata yapmayın. 🙂

Umarım faydalı olmuştur. Elimden geldiğince bu seriyi devam ettireceğim.

Bağlantılar

1- Bourne shell, https://en.wikipedia.org/wiki/Bourne_shell

2- GNU Bash, https://www.gnu.org/software/bash/

3- Shebang (Unix), https://en.wikipedia.org/wiki/Shebang_(Unix)

“Shell Script #0 – (Giriş)” için bir yorum

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir