İçeriğe geç
academia.sh

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:

  1. Yalnızca argümandan çalışanlar. mkdir, chmod, rm gibi komutlar iş için dosya adına ihtiyaç duyar; standart girdiyi okumazlar.
  2. Yalnızca standart girdiden çalışanlar. tr bunun tipik örneğidir; dosya adı argümanı almaz.
  3. İkisini de kabul edenler. sort, wc, grep, cat gibi 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ı >&2 ile 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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat