Ders 02 / 20
Kabuk Nedir
İstem, komut satırının sözcüklere ayrılması, açılımların komuttan önce yapılması, seçenek biçimleri, yerleşik komutlar ve çıkış durumu.
İçindekiler
Önceki ders kabuğu, komutları yorumlayan değiştirilebilir bir program olarak tanımladı. Bu tanım henüz bir şey açıklamaz: kabuk yazılan satırı tam olarak ne yapar?
Sorunun yanıtı, komut satırının en sık yapılan hatalarını da açıklar. Boşluk içeren bir dosya adı neden iki ayrı argümana bölünür, yıldız işaretini gerçekte kim yorumlar, bir komutun başarılı olup olmadığı nereden anlaşılır — hepsi tek bir ayrıştırma sürecinin sonucudur.
İstem
Kabuk, komut beklediğini istem (prompt) ile bildirir. İstemin içeriği yapılandırılabilir; kullanıcı adı, makine adı ve bulunulan dizin yaygın olarak gösterilir. Bu kursun örneklerinde istem tek bir karakterle gösterilir:
$ echo Merhaba Merhaba
$ ile başlayan satırlar yazılan komuttur; altındaki satırlar komutun ürettiği çıktıdır.
Belgelerde yerleşik bir gelenek vardır: sıradan kullanıcı istemi $, süper kullanıcı
istemi # ile gösterilir. Bir belgede # ile başlayan komut görülürse, o komutun
yönetici yetkisi gerektirdiği anlaşılır.
Satır Sözcüklere Bölünür
Kabuk satırı önce sözcüklere böler. Bölme, boşluk karakterleriyle yapılır ve ardışık boşluklar tek bir ayırıcı sayılır. İlk sözcük çalıştırılacak programın adıdır; kalan sözcükler ona argüman olarak geçirilir.
$ echo Merhaba dunya Merhaba dunya
Çıktıda dört boşluk yerine bir boşluk vardır. Bunun nedeni echo komutunun boşlukları
sıkıştırması değildir: echo iki argüman almıştır — Merhaba ve dunya — ve onları tek
boşlukla birleştirerek yazdırmıştır. Aradaki boşluklar echo çalışmadan önce yok
olmuştur.
Argüman sayısı doğrudan sayılabilir:
$ dosya="olcum 01.csv" $ set -- $dosya; echo $# 2 $ set -- "$dosya"; echo $# 1
$# argüman sayısını verir. Değişkenin değeri tırnaksız yazıldığında kabuk onu iki
sözcüğe bölmüş, tırnak içinde yazıldığında tek sözcük olarak bırakmıştır. Boşluk içeren
dosya adlarının neden tırnak içinde yazılması gerektiğinin nedeni budur; aksi hâlde komut,
var olmayan iki dosya arar.
Aynı fark, sözcük sınırlarını görünür kılan bir yazdırma biçimiyle de gösterilebilir:
$ printf '[%s]\n' $dosya [olcum] [01.csv] $ printf '[%s]\n' "$dosya" [olcum 01.csv]
Açılımlar Komuttan Önce Yapılır
Sözcüklere bölme tek işlem değildir. Kabuk, program çalışmadan önce sözcükler üzerinde
birkaç açılım (expansion) uygular. Bu kursta üçü kullanılır: değişken açılımı ($ad),
dosya adı açılımı (*, ?) ve ev dizini açılımı (~).
Belirleyici nokta şudur: açılımı yapan kabuktur, çalıştırılan program değil. Program yalnızca açılım sonucunu görür.
$ echo /usr/bin/zc* /usr/bin/zcat /usr/bin/zcmp $ ls /usr/bin/zc* /usr/bin/zcat /usr/bin/zcmp
İki komut da aynı iki dosya adını üretmiştir. ls komutuna * karakteri hiç
ulaşmamıştır; kabuk deseni eşleşen dosya adlarıyla değiştirmiş, ls iki hazır argüman
almıştır. echo ile ls çıktısı arasındaki tek fark, ls sütun hizalaması yapmasıdır.
Bunun iki sonucu vardır. Birincisi, desen hiçbir dosyayla eşleşmezse kabuk deseni olduğu
gibi bırakır ve program * içeren anlamsız bir ad alır. İkincisi ve daha önemlisi, bir
komutun ne yapacağı önceden görülebilir: komutun başına echo yazmak, kabuğun
üreteceği argüman listesini çalıştırmadan gösterir. Bu, silme işlemleri dersinde bir
güvenlik alışkanlığına dönüşecektir.
Tırnak, açılımı da durdurur:
$ echo "/usr/bin/zc*" /usr/bin/zc*
Çift tırnak dosya adı açılımını ve sözcük bölmeyi engeller, değişken açılımını engellemez. Tek tırnak hepsini engeller: tek tırnak içindeki metin harfi harfine korunur.
Seçenekler ve Argümanlar
Bir komut satırının argümanları iki türlüdür. Seçenek (option) komutun davranışını değiştirir ve gelenek olarak tire ile başlar; kalanlar komutun üzerinde çalışacağı nesnelerdir.
Seçeneklerin üç yazım biçimi vardır ve üçü de aynı sonucu verir:
$ ls -l -a /home total 16 drwxr-xr-x 1 root root 4096 Jul 26 18:53 . drwxr-xr-x 1 root root 4096 Jul 26 18:46 .. drwxr-x--- 3 ogrenci ogrenci 4096 Jul 26 18:49 ogrenci $ ls -la /home total 16 drwxr-xr-x 1 root root 4096 Jul 26 18:53 . drwxr-xr-x 1 root root 4096 Jul 26 18:46 .. drwxr-x--- 3 ogrenci ogrenci 4096 Jul 26 18:49 ogrenci
Tek harfli seçenekler tek tire ile yazılır ve birleştirilebilir: -l -a ile -la aynı
şeydir. Uzun seçenekler iki tire ile yazılır (--all) ve birleştirilemez; her biri ayrı
sözcüktür. Uzun seçenek biçimi POSIX’te tanımlı değildir, GNU araç ailesinin eklentisidir;
taşınabilir olması gereken yerlerde tek harfli biçim tercih edilir.
Tire ile başlayan bir dosya adı varsa sorun çıkar: komut onu seçenek sanır. Bunun için
-- ayıracı vardır. -- sözcüğünden sonrası seçenek olarak yorumlanmaz. Bu ayıracın
neden bir güvenlik konusu olduğu, silme dersinde görülecektir.
Yerleşik Komut ve Dış Program
Her komut ayrı bir program değildir. Bazı komutlar kabuğun kendi içinde gerçekleştirilmiştir; bunlara yerleşik komut (builtin) denir. Bir adın hangisi olduğu sorulabilir:
$ type -a cd pwd echo cd is a shell builtin pwd is a shell builtin pwd is /usr/bin/pwd pwd is /bin/pwd echo is a shell builtin echo is /usr/bin/echo echo is /bin/echo
Üç farklı durum görünür. cd yalnızca yerleşiktir. pwd ve echo hem yerleşiktir hem de
dış program olarak vardır; bu durumda yerleşik olan kazanır.
cd’nin yerleşik olması bir tercih değil, zorunluluktur. Bir programın çalışma dizini
kendi sürecine aittir; ayrı bir program olarak çalışan cd, kendi dizinini değiştirip
sonlanır ve kabuğun dizini olduğu yerde kalırdı. Dizin değiştirmek için komutun kabuğun
kendi süreci içinde çalışması gerekir.
echo’nun hem yerleşik hem dış program olması ise taşınabilirlik içindir: kabuğu olmayan
ortamlarda da çağrılabilmesi gerekir. İki gerçekleştirimin davranışı tam olarak aynı
değildir; bu nedenle biçimli çıktıda echo yerine printf tercih edilir.
Çıkış Durumu
Her komut sonlandığında geriye bir tam sayı bırakır: çıkış durumu (exit status). Sözleşme tersine kuruludur — sıfır başarıyı, sıfırdan farklı her değer bir başarısızlığı bildirir. Tek bir başarı, sayısız başarısızlık türü olduğu için bu yön seçilmiştir.
Son komutun durumu $? değişkeninde tutulur:
$ true; echo $? 0 $ false; echo $? 1 $ ls /yokdizin; echo $? ls: cannot access '/yokdizin': No such file or directory 2
ls başarısızlığı hem bir hata iletisiyle hem de sıfırdan farklı bir durumla bildirir.
İleti insan içindir; durum kodu, komutları birbirine bağlayan betikler içindir.
İki değer kabuğun kendisinden gelir ve ayırt edilmesi gerekir:
$ lss -l bash: lss: command not found $ echo $? 127
127 komutun bulunamadığını, 126 bulunduğunu ama çalıştırılamadığını bildirir. Birincisi bir arama sorunudur, ikincisi bir izin sorunu. Bu iki sayının farkı, sonraki dersin ve izinler konusunun tam olarak neyi çözdüğünü gösterir.
Hata iletilerinin nereye yazıldığı da ayrı bir konudur: normal çıktı ile hata çıktısı iki ayrı akıştır ve birbirinden bağımsız yönlendirilebilir. Bu ayrımın kullanımı Kabuk Programlama kursuna aittir.
Özet
- Kabuk satırı önce sözcüklere böler; ilk sözcük program adı, kalanlar argümandır.
- Değişken, dosya adı ve ev dizini açılımları program çalışmadan önce kabukta yapılır; program yalnızca sonucu görür.
- Çift tırnak sözcük bölmeyi ve dosya adı açılımını durdurur, değişken açılımını durdurmaz; tek tırnak hepsini durdurur.
- Tek harfli seçenekler birleştirilebilir, uzun seçenekler birleştirilemez;
--ayıracı seçenek yorumlamasını bitirir. - Yerleşik komutlar kabuğun kendi sürecinde çalışır;
cdbu nedenle yerleşik olmak zorundadır. - Çıkış durumunda sıfır başarıyı gösterir; 127 komutun bulunamadığını, 126 çalıştırılamadığını bildirir.
Sonraki Adım
Komutlar artık üzerinde çalışacak dosyalara ihtiyaç duyar. Ancak dosyalar rastgele yerleştirilmemiştir: kök dizinden başlayan hiyerarşinin her dalının belirli bir anlamı vardır. Sonraki ders bu yerleşimi tanıtır, mutlak ve göreli yol ayrımını kurar ve kurs boyunca geliştirilecek proje ağacını oluşturur.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.