Bash Kabuk Betikleme/Basit Komutlar

Basit bir komut, boşluk veya tab ile ayrılmış kelimelerden oluşur. İlk kelime komutun ismiyken geri kalan kelimeler komutun argümanları olarak tanımlanır. Önceki başlıkta bazı basit komut örnekleri görmüştük. Burada birkaç tane daha var:

  • cd ..
    • Bu komut cd ("change directory" = dizin değiştir; dosya sistemi içerisinde yolculuk yapmak için kullanılır)'yi bir dizin üste çıkmak için kullanmaktadır.
    • .. işareti "üst dizin" anlamına gelir. Örneğin /foo/bar/../baz.txt ile belirtilen konum, /foo/baz.txt konumunun eş anlamlısıdır.
  • rm foo.txt bar.txt baz.txt
    • rm komutunun yüklü geldiğini varsayarsak bu program mevcut dizindeki foo.txt, bar.txt ve baz.txt isimli dosyaları siler.
    • Bash, harici olan rm programını yapılandırılabilir dizin listesinde rm isimli çalıştırılabilir bir dosya arayarak bulur.
  • /foo/bar/baz bip.txt
    • Bu komut, /foo/bar/baz konumunda bulunan programı çalıştırır ve bip.txt'de bulunan argümanı kullanır.
    • /foo/bar/baz çalıştırılabilir olmalıdır.
    • Dikkat: Eğik çizgi ve dosya isimleri arasında BOŞLUK OLMAMASINA dikkat edin. Eğer rm -r / foo gibi boşluk nedeniyle kök dizini hedef alan bir komutu yönetici haklarıyla çalıştırırsanız bilgisayarınızın kök dizini silinebilir ve ayvayı yersiniz.
    • Eğer /foo/bar/baz ikili program yerine bir metin dosyasıysa ve ilk satırı #! ile başlıyorsa o satırın hatırlatıcısı bu dosyayı çalıştırmak için gerekli olan yorumlayıcıyı (interpreter) belirler. Örneğin eğer /foo/bar/baz konumunda bulunan dosyanın ilk satırı #!/bin/bash ise üstteki komut /bin/bash /foo/bar/baz bip.txt ile eş anlamlıdır.

/foo/bar/baz ile yapılan örnek, herhangi bir program gibi çalışabilen Bash betiklerinin yapılabileceğini gösteren özel bir not içeriyor. Yalnızca #!/bin/bash ifadesinin bir betiğin ilk satırına konulması ve okunup çalıştırılabilmesi için doğru dosya izinlerine sahip olması o betiğin bir program gibi çalışması için yeterli. Bir hatırlatma olarak bu kitaptaki tamamlanmış tüm kabuk betikleri #!/bin/bash ile başlayacaktır.

Gezinme değiştir

İlk örnekte gördüğümüz üzere cd komutu belirtilen argümanlar ile gezinmeye yarar. Unix ve GNU/Linux gibi Unix benzeri sistemlerde göreceli ve mutlak olmak üzere iki yol türü vardır. Göreceli yollar bulunduğunuz yola göre konumlanırken mutlak yollar nettir. Bu örnekte belirtilen mutlak yola gidiliyor:

cd 'örnek/dizin'

Göreceli yol gezinmesi için çeşitli kısayolları mümkün kılan belirli argümanlar vardır. 2 dizin üste çıkmak için şu argümanı kullanmalısınız:

cd ../../

Mevcut konumunuzdan önce bulunduğunuz konuma dönmek için şu argümanı kullanabilirsiniz:

cd -
  İpucu:

cd'yi argümansız şekilde kullanarak sisteminizin varsayılan ev dizinine hızlıca gidebilirsiniz.

Şu an üzerinde olduğunuz yolu öğrenmek için yaygın Unix araçlarından pwd komutunu kullanabilirsiniz.

Alıntılama değiştir

Yukarıda rm foo.txt bar.txt baz.txt komutunun foo.txt, bar.txt, ve baz.txt isimli üç dosyayı sildiğini gördük. Bu, Bash'in komutları boşluğa göre 4 farklı kelimeye ayırmasından ve o 3 kelimenin rm programının argümanlarına dönüşmesinden kaynaklanıyor. Peki ya isminde boşluk olan bir dosyayı silmek istersek ne yapmalıyız?

  Dikkat:

Unix, GNU/Linux dağıtımları ve öbür Unix benzeri sistemlerde dosya isimleri boşluk, tab, yeni satır ve hatta kontrol karakterlerine sahip olabilir.

Bash bu durumda işe yarayabilecek bazı alıntılama tekniklerine sahiptir. Bu teknikler arasında tek tırnak işaretleri ' ve çift tırnak işaretleri " en yaygın olanlardır. Bu iki komut da bu dosya.txt isimli bir dosyayı silecektir:

rm 'bu dosya.txt'
rm "bu dosya.txt"

Tırnak işaretleri içindeki boşluk karakterleri, kelime ayırma özelliklerini kaybeder. Normalde yukarıdaki gibi tüm kelime tırnak içine alınsa da yalnızca boşluğu this' 'file.txt veya this" "file.txt olarak tırnak içine almak da işe yarar.

Öbür sıklıkla kullanılan bir alıntılama mekanizması da ters eğik çizgi \ ifadesidir ancak yalnızca bir karakteri alıntıladığı (veya "atladığı") için tırnaklardan biraz farklı çalışır. Alttaki komut üstteki örneklerle aynı işlevi görür:

rm bu\ dosya.txt

Tüm bu durumlarda görülebildiği üzere alıntılama karakterleri programa dahil edilmemiştir. (Buna alıntı silimi denir.) Bu nedenle rm komutu bu alıntıların çalıştırıldığına dair bilgi sahibi değildir. Örneğin rm foo.txt veya rm 'foo.txt' komutları rm için aynıdır.

Dosya ismi uzantıları ve yaklaşık uzantılar değiştir

Bash yaygın kullanılan argümanları programlara geçirmek için uzantı olarak bilinen bazı özel işaretleri destekler.

Bu işaretlerden birisi, *.txt gibi bir desenin bu desene uyan tüm dosyalara tekabül etmesini sağlayan dosya ismi uzantısıdır. Örneğin mevcut dizin foo.txt, bar.txt, bu dosya.txt, ve başka bir.şey gibi dosyaları barındırıyorsa şu komut:

echo *.txt

bu komut ile aynı görevi görecektir:

echo 'bar.txt' 'foo.txt' 'bu dosya.txt'

Burada * ifadesi "sıfır veya daha fazla karakter" anlamına gelir. Başka özel desen karakterleri (örneğin "tam olarak tek karakter" anlamına gelen soru işareti ?) ve desen eşleştirme kuralları da vardır ancak * ifadesinin bu kullanımı desenlerin en yaygın kullanımıdır.

Dosya isim uzantısı mevcut dizindeki dosyalarla sınırlı değildir. Örneğin eğer /usr/bin dizini içindeki t*.sh desenine uyan tüm dosyaları sıralamak istiyorsak şu komutu yazabiliriz:

echo /usr/bin/t*.sh

Bu komutu şu şekilde genişletebiliriz:

echo /usr/bin/test.sh /usr/bin/time.sh

Eğer hiçbir dosya belirtilen desene uymuyorsa herhangi bir ikame yaşanmaz. Örneğin şu komut yalnızca asfasefasef*avzxv çıktısı verecek:

echo asfasefasef*avzxv
  Dikkat:

Eğer herhangi bir dosya ismi tire - ile başlıyorsa dosya ismi uzantısı şaşırtıcı sonuçlar verebilir. Örneğin eğer bir dizin -n ve tmp.txt isminde 2 dosya içeriyorsa cat * komutu cat -n tmp.txt olarak genişler ve cat komutu -n ifadesini bir dosya ismi yerine bir seçenek argümanı olarak çalıştıracaktır. Böyle durumlara karşı cat ./-n ./tmp.txt veya cat -- -n tmp.txt şeklinde doğru genişleyip çalışmaları için tireli ifadeleri cat ./* veya cat -- * olarak yazmak daha iyidir.

Peki ya eğer ismi *.txt olan bir dosyayı belirtmek istiyorsak ne yapmalıyız? (Evet, dosya isimleri yıldız içerebilir!) O halde daha önce bahsettiğimiz alıntılama tekniklerinden tırnak işaretlerini kullanabiliriz:

cat '*.txt'
cat "*.txt"

İki komut da .txt uzantısını içeren dosyalar yerine *.txt isimli dosyanın içeriğini çıkartacaktır.

Başka benzer bir uzantı da yaklaşık uzantısıdır. Yaklaşık uzantısı çok daha fazla özelliğe sahiptir ancak en önemli özelliği yalnızca yaklaşık işaretine ~ veya eğik çizgi ile yaklaşık işaretine ~/ sahip bir kelimede yaklaşık işaretini dosyanın mevcut kullanıcının ev dizinine kadar olan konumuyla değiştirmesidir. Örneğin şu komut, mevcut kullanıcının ev dizininde *.txt desenine uyan tüm dosyaları yazdıracaktır:

echo ~/*.txt

Ayraç uzantıları değiştir

Ayraç uzantısı, dosya uzantısına benzer şekilde birden fazla benzer argümanı belirtmek için kullanılır. Aşağıdaki 4 komut birbirinin aynısıdır:

ls dosya1.txt dosya2.txt dosya3.txt dosya4.txt dosya5.txt
ls dosya{1,2,3,4,5}.txt
ls dosya{1..5..1}.txt
ls dosya{1..5}.txt

İlk komut her bir argümanı açıkça sıralar. Öbür üç komut belirtilen argümanları kısaca ifade etmek için ayraç uzantısı kullanır. İkinci komutta 1'den 5'e kadar olan ifadeler virgülle ayrılarak verilmiş. Üçüncü komutta ise numaralı bir sıra (1'den 5'e kadar, 1 arttırılarak) verilmiş. Dördüncü komut üçüncü komut ile aynı ancak ..1 ifadesi örtük.

Dosyaları ayrıca tersten de sıralayabiliriz.

ls dosya5.txt dosya4.txt dosya3.txt dosya2.txt dosya1.txt
ls dosya{5,4,3,2,1}.txt
ls dosya{5..1..-1}.txt
ls dosya{5..1}.txt

Son değer başlangıç değerinden düşük olduğu için örtük ifade -1 olmalıdır.

Bash'de bir komutun ilk kelimesi çalıştırılacak program olduğundan komutu şu şekil de yazabiliriz:

{ls,dosya{1..5}.txt}

Ayraç uzantıları aynı dosya ismi uzantıları gibi '{', "{", or \{ gibi alıntılama mekanikleriyle devre dışı bırakılabilir.

Çıktı yönlendirme değiştir

Bash bir komutun standart çıktısının konsol yerine bir dosyaya gönderilmesine izin verir. Örneğin yaygın bir araç komutu olan cat

bir dosyanın içeriğini standart çıktı olarak yazdırır. Eğer bu standart çıktıyı bir dosyaya yönlendirirsek bu durumda bir dosyanın içeriğini başka bir dosyaya kopyalama işlemini gerçekleştirmiş oluruz.

Eğer hedef dosyanın içeriğinin komut çıktısı tarafından üstüne yazılmasını istiyorsak şu ifadeyi kullanmalıyız:

cat girdi.txt > çıktı.txt

Eğer hedef dosyanın içeriğinin korunup komut çıktısını dosyanın sonuna iliştirmek istiyorsak şu ifadeyi kullanacağız:

cat girdi.txt >> çıktı.txt

Ancak bir programın konsola yazdığı her şey standart çıktı formatında olmayabilir. Çoğu program hata çıktısı ve "giriş" veya "yan-kanal" mesajları için standart hata formatını kullanıyor. Eğer standart hata formatının da standart çıktıya dahil edilmesini istiyorsak şu ifadelerden birini kullanabiliriz:

cat girdi.txt &>> çıktı.txt
cat girdi.txt >> çıktı.txt 2>&1

Eğer hata çıktısının standart çıktıdan ayrı bir dosyaya yazılmasını istiyorsak şu ifadeyi kullanmalıyız:

cat girdi.txt >> çıktı.txt 2>> hata.txt

Aslında standart çıktıya dokunmayıp yalnızca hata çıktısını da yönlendirebiliriz:

cat girdi.txt 2>> hata.txt

Yukarıda gösterilen tüm örneklerde çıktıyı yönlendirme hedefindeki içeriğe iliştirmek yerine üstüne yazmak için >> ifadesini > ile değiştirebiliriz.

İlerleyen bölümlerde bu çıktı yönlendirmesiyle yapılabilecek daha gelişmiş örneklere bakacağız.

Girdi yönlendirme değiştir

Bash bir programın çıktısının dosyaya yönlendirilmesine izin verdiği gibi program girdisini de dosyadan yönlendirebilir. Örneğin araç komutu olan cat aşağıdaki örnekte belirtilen dosyadaki girdiyi çıktısına kopyalayıp girdi.txt içeriğini konsola yazdırıyor:

cat < girdi.txt

Halihazırda gördüğümüz gibi cat zaten girilen dosyanın içeriğini yazdırmak için kulllanılabilen bir komut olduğundan yönlendirme bu örnekte gerekli değildir ve aynı komut şu şekilde de yazılabilir:

cat girdi.txt

Bu bir istisnadan ziyade kuraldır. Konsoldan girdi alabilen çoğu sık kullanılan Unix aracı girdilerini belirtilen dosyadan alma özelliğine sahiptir. Doğrusu cat de dahil olmak üzere birçok komut birden fazla dosyayı girdi olarak alarak yukarıdaki örnekten daha esnek kullanıma sahip olabilir. Aşağıdaki örnek sırasıyla girdi1.txt ve girdi2.txt'yi yazdırıyor:

cat girdi1.txt girdi2.txt

Bununla beraber girdi yönlendirmenin önemli olduğu kullanım alanları vardır ve onları ileriki örneklerde göreceğiz.

Bağlantı hatlarına giriş değiştir

Bu bölümün kapsamının dışında olmasına karşın artık bağlantı hatlarına bakmak için gerekli bilgiye sahibiz. Bir bağlantı hattı (pipeline), bağlantı karakteri | ile ayrılarak yazılmış komutlar serisidir. Serideki her bir komut aynı anda çalışır ve her bir komutun çıktısı bir sonrakinin girdisi olarak kullanılır.

Örneğin şu bağlantı hattını inceleyelim:

cat girdi.txt | grep foo | grep -v bar

cat aracını daha önce görmüştük. cat girdi.txt komutu basitçe girdi.txt dosyasını standart çıktısı olarak yazdırıyor. grep programı belirtilen şablona uygun olan ifadeleri filtreleyen (Unix konuşma dilinde "grepleyen") yaygın bir Unix aracıdır. Yukarıdaki örnekte de grep foo komutu belirtilen girdide foo ifadesini taşıyan satırları yazdıracaktır. grep -v bar komutu ise şablonu tersine çeviren -v argümanına sahiptir yani komut girdide bar ifadesini taşımayan tüm satırları yazdıracaktır. Her komutun girdisi bir önceki komutun çıktısı olduğuna göre bağlantı hattı girdi.txt dosyasındaki satırlardan sadece foo ifadesini taşıyan ve bar ifadesini taşımayanları yazdıracaktır.