Ders 01 / 24
Standart Girdi, Çıktı ve Hata
Üç standart akış, dosya tanıtıcı numaraları, veriyle tanı iletisinin ayrılması ve süzgeç modeli.
İçindekiler
Linux’a Giriş kursunda komutlar tek tek çalıştırıldı: dizin listelendi, dosya kopyalandı, izin değiştirildi. Her komutun bir çıktısı oldu ve o çıktı ekrana yazıldı. Ekran, işin bittiği yerdi.
Bu kurs o varsayımı kaldırır. Kabuğun asıl gücü, bir komutun ürettiği veriyi başka bir komuta yem yapabilmesinden gelir; bunun için de çıktının nereye gittiğinin komut tarafından değil, komutu çağıran tarafından belirlenmesi gerekir. İlk soru şudur: bir komut yazdığı veriyi tam olarak nereye yazar?
Üç Akış
Bir süreç (process) başlatıldığında, kabuk ona üç adet açık akış (stream) devreder. Her akış bir tam sayıyla, dosya tanıtıcısı (file descriptor) ile anılır:
| Numara | Ad | Yön | Varsayılan bağlantı |
|---|---|---|---|
| 0 | standart girdi (stdin) | okuma | klavye |
| 1 | standart çıktı (stdout) | yazma | ekran |
| 2 | standart hata (stderr) | yazma | ekran |
Bu numaralar sözleşmedir, keşif değil: her program çalışmaya başladığında 0, 1 ve 2 numaralı tanıtıcıların açık olduğunu varsayar. Program bu tanıtıcıların ucunda ne olduğunu bilmez ve bilmemelidir. Uç, bir terminal olabilir; bir dosya, bir boru veya bir ağ bağlantısı da olabilir.
Bu bilgisizlik bir eksiklik değil, tasarımın kendisidir. Komut “ekrana yaz” demez, “1 numaralı tanıtıcıya yaz” der. Nereye gideceğine çağıran karar verir.
Neden İki Ayrı Çıkış Akışı
Yazma yönünde iki akış olması ilk bakışta gereksiz görünür. Gerekçesi şudur: bir komutun ürettiği iki tür metin vardır ve bunlar farklı yerlere gitmelidir.
- Veri, komutun asıl ürünüdür: dosya listesi, satır sayısı, süzülmüş metin. Başka bir komuda girdi olabilecek olan budur. Standart çıktıya gider.
- Tanı iletisi (diagnostic message), insan içindir: hata bildirimi, uyarı, ilerleme bilgisi. Bir sonraki komuda girdi olarak kullanılmamalıdır. Standart hataya gider.
Ayrım pratikte hemen görülür. Aşağıdaki komut var olan bir dosya ile var olmayan bir adı birlikte listeler:
ls erisim.log yok.txt
ls: yok.txt: No such file or directory erisim.log
İki satır aynı ekranda göründü, ama aynı akıştan gelmediler. Bunu doğrulamak için
akışlardan birini ıskartaya çıkarmak yeterlidir. /dev/null, kendisine yazılan her şeyi
yutan özel bir aygıt dosyasıdır:
ls erisim.log yok.txt 2>/dev/null
erisim.log
ls erisim.log yok.txt 1>/dev/null
ls: yok.txt: No such file or directory
2> ve 1> gösterimlerinin ayrıntısı sonraki dersin konusudur; burada önemli olan
sonuçtur. İlk çağrıda yalnızca veri, ikincisinde yalnızca tanı iletisi kaldı. Demek ki
ls, bulamadığı dosya için ürettiği iletiyi bilerek ikinci akışa yazmıştır.
Bu davranış bir gelenek değil, uyulması beklenen bir kuraldır. Kendi betiklerinizde uyarıları standart çıktıya yazarsanız, betiğinizin çıktısını işleyen bir sonraki komut uyarı metnini veri sanır ve bozulur.
Kendi İletinizi Doğru Akışa Yazmak
>&2 eki, bir komutun standart çıktısını standart hataya bağlar. Bir betikte uyarı
üretmenin doğru yolu budur:
uyar() { printf 'uyari: %s\n' "$1" >&2; }
uyar "kutuk bulunamadi"
echo "rapor gövdesi"
Bu iki satırın çıktısı, hangi akışa baktığınıza göre değişir. Yalnızca veriyi istediğinizde:
{ uyar "kutuk bulunamadi"; echo "rapor gövdesi"; } 2>/dev/null
rapor gövdesi
Yalnızca tanı iletisini istediğinizde:
{ uyar "kutuk bulunamadi"; echo "rapor gövdesi"; } 1>/dev/null
uyari: kutuk bulunamadi
Kurs boyunca yazılacak betikte bu kural değişmeyecek: raporun kendisi standart çıktıya, raporla ilgili her açıklama standart hataya gider.
Akışlar Bağımsız Tamponlanır
İki akışın ekranda göründüğü sıra, komutun onları yazdığı sıra olmayabilir. Yukarıdaki
ls çağrısında hata iletisi, veri satırından önce göründü. Bunun nedeni
tamponlama (buffering) farkıdır: standart hata genellikle tamponsuz veya satır
tamponludur, standart çıktı ise bir dosyaya ya da boruya bağlıyken blok tamponludur.
Blok tamponlu akış, tamponu dolana veya süreç bitene kadar bekletilir.
İki akışı aynı dosyaya toplayınca sonuç görülebilir:
ls erisim.log yok.txt > hepsi.txt 2>&1 cat hepsi.txt
ls: yok.txt: No such file or directory erisim.log
Buradan çıkan kural: iki akışın birbirine göre sırasına güvenmeyin. Bir betiğin çıktısını hata iletileriyle birlikte kütüğe yazıyorsanız, satırların kronolojik sırada olacağını varsaymayın; sıra gerekiyorsa her satıra kendi zaman damgasını yazın.
Süzgeç Modeli
Standart girdi, akışların en az göze çarpanıdır çünkü etkileşimli kullanımda çoğu komut onu kullanmaz. Oysa kabuğun bileşim gücü tam olarak buradan gelir.
Süzgeç (filter), standart girdisinden okuyup standart çıktısına yazan komuttur.
Süzgeçler dosya adı bilmez, konum bilmez; yalnızca kendilerine akan metni dönüştürür.
sort, tr, wc, head, grep bu sınıftadır.
tr 'a-z' 'A-Z' <<< 'kabuk programlama'
KABUK PROGRAMLAMA
Komutlar girdi kaynağı bakımından üç öbeğe ayrılır:
- Yalnızca argümandan çalışanlar.
mkdir,chmod,rmgibi komutlar iş için dosya adına ihtiyaç duyar; standart girdiyi okumazlar. - Yalnızca standart girdiden çalışanlar.
trbunun tipik örneğidir; dosya adı argümanı almaz. - İkisini de kabul edenler.
sort,wc,grep,catgibi komutlar dosya adı verilirse onu, verilmezse standart girdiyi okur.
Üçüncü öbek en yaygınıdır ve iki farklı yazımı vardır:
wc -l erisim.log
30 erisim.log
wc -l < erisim.log
30
Fark yalnızca biçimsel değildir. İlk çağrıda wc dosyayı kendisi açar; adını bildiği
için çıktısına yazar. İkincisinde wc yalnızca bir akış görür; dosyanın adını bilmez,
dolayısıyla yazamaz. Ne zaman hangisinin istendiği duruma bağlıdır: çok dosyalı raporda
ad gerekir, sayıyı bir değişkene almak istediğinizde ad engeldir.
Satır sayısını hizalayarak yazan gerçekleştirimler sayının önüne boşluk koyar; GNU coreutils sürümü koymaz. Sayıyı doğrudan karşılaştırmada kullanacaksanız bu boşluk sorun çıkarır — ilerleyen derslerde aritmetik genişletme bu farkı soğurur.
Üçüncü öbekteki komutların çoğu, dosya adı yerine tek bir tire (-) kabul eder ve bunu
“standart girdi” diye yorumlar. Dosya listesinin ortasına akış sokmak gerektiğinde
kullanılır:
head -2 erisim.log | cat -n -
1 10.0.0.12 - - [07/Feb/2024:09:12:44 +0000] "GET /index.html HTTP/1.1" 200 5120
2 10.0.0.31 - - [07/Feb/2024:09:12:51 +0000] "GET /statik/stil.css HTTP/1.1" 200 2048
Tirenin bu anlamı çekirdek düzeyinde değil, her komutun kendi içinde tanımlıdır; genel bir kural değil yaygın bir sözleşmedir.
Kursun Çalışma Dosyası
Bu kurs boyunca tek bir veri kümesi kullanılacak: bir web sunucusunun erişim kütüğü
(log). Aşağıdaki otuz satırı erisim.log adıyla kaydedin; sonraki her ders bu dosya
üzerinde ilerleyecek.
10.0.0.12 - - [07/Feb/2024:09:12:44 +0000] "GET /index.html HTTP/1.1" 200 5120 10.0.0.31 - - [07/Feb/2024:09:12:51 +0000] "GET /statik/stil.css HTTP/1.1" 200 2048 10.0.0.12 - - [07/Feb/2024:09:13:02 +0000] "GET /urun/12 HTTP/1.1" 200 8410 172.16.0.9 - - [07/Feb/2024:09:14:19 +0000] "GET /yok.html HTTP/1.1" 404 512 10.0.2.7 - - [07/Feb/2024:09:15:30 +0000] "POST /giris HTTP/1.1" 302 0 10.0.2.7 - - [07/Feb/2024:09:15:31 +0000] "GET /panel HTTP/1.1" 200 12040 10.0.0.31 - - [07/Feb/2024:09:16:04 +0000] "GET /urun/45 HTTP/1.1" 200 7330 192.168.1.5 - - [07/Feb/2024:09:17:22 +0000] "GET /api/veri HTTP/1.1" 500 180 10.0.0.12 - - [07/Feb/2024:09:18:00 +0000] "GET /api/veri HTTP/1.1" 200 3300 172.16.0.9 - - [07/Feb/2024:09:18:47 +0000] "GET /gizli HTTP/1.1" 403 290 10.0.0.31 - - [07/Feb/2024:09:19:12 +0000] "GET /index.html HTTP/1.1" 200 5120 10.0.2.7 - - [07/Feb/2024:09:20:05 +0000] "GET /urun/12 HTTP/1.1" 200 8410 192.168.1.5 - - [07/Feb/2024:09:21:38 +0000] "GET /api/veri HTTP/1.1" 500 180 10.0.0.12 - - [07/Feb/2024:09:22:10 +0000] "GET /statik/stil.css HTTP/1.1" 304 0 172.16.0.9 - - [07/Feb/2024:09:23:55 +0000] "GET /yok.html HTTP/1.1" 404 512 10.0.0.31 - - [07/Feb/2024:09:24:41 +0000] "POST /api/veri HTTP/1.1" 201 96 10.0.2.7 - - [07/Feb/2024:09:25:19 +0000] "GET /index.html HTTP/1.1" 200 5120 192.168.1.5 - - [07/Feb/2024:09:26:33 +0000] "GET /urun/45 HTTP/1.1" 200 7330 10.0.0.12 - - [07/Feb/2024:09:27:02 +0000] "GET /panel HTTP/1.1" 200 12040 172.16.0.9 - - [07/Feb/2024:09:28:14 +0000] "GET /eski-sayfa HTTP/1.1" 301 0 10.0.0.31 - - [07/Feb/2024:09:29:48 +0000] "GET /api/veri HTTP/1.1" 200 3300 10.0.2.7 - - [07/Feb/2024:09:30:26 +0000] "GET /statik/stil.css HTTP/1.1" 200 2048 192.168.1.5 - - [07/Feb/2024:09:31:07 +0000] "GET /yok.html HTTP/1.1" 404 512 10.0.0.12 - - [07/Feb/2024:09:32:53 +0000] "GET /urun/12 HTTP/1.1" 200 8410 10.0.0.31 - - [07/Feb/2024:09:33:39 +0000] "GET /gizli HTTP/1.1" 403 290 172.16.0.9 - - [07/Feb/2024:09:34:11 +0000] "GET /index.html HTTP/1.1" 200 5120 10.0.2.7 - - [07/Feb/2024:09:35:44 +0000] "POST /api/veri HTTP/1.1" 500 180 192.168.1.5 - - [07/Feb/2024:09:36:58 +0000] "GET /panel HTTP/1.1" 200 12040 10.0.0.12 - - [07/Feb/2024:09:37:20 +0000] "GET /urun/45 HTTP/1.1" 200 7330 10.0.0.31 - - [07/Feb/2024:09:38:05 +0000] "GET /yok.html HTTP/1.1" 404 512
Her satırın alanları boşlukla ayrılmıştır: istemci adresi, iki kullanılmayan alan, köşeli ayraç içinde zaman damgası, tırnak içinde istek satırı (yöntem, yol, protokol), yanıt durum kodu ve gönderilen bayt sayısı. Kursun sonunda bu dosyayı okuyup özet rapor üreten, hataya dayanıklı ve zamanlanmış olarak çalışan bir betik yazılmış olacak.
Özet
- Her sürece üç akış devredilir: 0 numaralı standart girdi, 1 numaralı standart çıktı, 2 numaralı standart hata. Program bu tanıtıcıların ucunda ne olduğunu bilmez.
- Komutun asıl ürünü olan veri 1’e, insana yönelik tanı iletileri 2’ye yazılır; kendi
betiklerinizde uyarıları
>&2ile ikinci akışa göndermek bu sözleşmeyi sürdürür. - İki akış bağımsız tamponlandığı için birbirlerine göre sıraları güvence altında değildir.
- Süzgeç, standart girdisinden okuyup standart çıktısına yazan ve dosya adı bilmeyen komuttur; kabuğun bileşim gücü bu modelden gelir.
- Bir komuta dosya adı vermekle akış bağlamak eşdeğer değildir: adı bilen komut onu çıktısına da yazabilir.
Sonraki Adım
Bu derste akışların uçlarını 2>/dev/null gibi gösterimlerle değiştirdik ama gösterimin
kendisini açıklamadık. Sonraki ders yönlendirme işleçlerini kuralıyla ele alır: dosyaya
yazma ile ekleme arasındaki fark, iki akışı tek dosyada toplamanın doğru sırası ve
yönlendirmelerin neden soldan sağa değerlendirildiği.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.