Linux’ta Girdi – Çıktı Yönlendirme

Linux’ta, çalıştırdığınız komutların çıktısını bir dosyaya ya da başka bir programa yönlendirmenizi gerektirecek durumlarla sıklıkla karşılaşırsınız. Bu yazıda, girdi – çıktı yönlendirme (input -output redirection) konusunu örneklerle anlatmaya çalışacağım.

Linux’ta her şey bir dosyadır (Bu görüşe karşı olan görüşler de mevcut. Genelleme yaparak konuşuyorum.). Her dosya, bir dosya tanımlayıcısı (file descriptor) ile ifade edilir. Çalıştırdığınız komutların çıktılarını gönderdiği noktayı ifade eden dosya tanımlayıcısı “1“dir. STDOUT, Standard Output olarak da bilinir. Benzer şekilde, bu komutların “hatalarının” gittiği nokta ise “2” ile ifade edilir. STDERR veya Standard Error olarak da bilinir. Son olarak, girdi (input) işlerinin dosya tanımlayıcı ise “0 (sıfır)“dır. STDIN veya Standard Input olarak da bilinir.

Bu sayılara ihtiyacımız olacak.

Standard Output (STDOUT, Standart Çıktı)

STDOUT, çıktıları varsayılan olarak terminalinize gönderir. Örneğin, “ls” programını çalıştırdığınızda, bu komutun çıktısı terminalinize düşer:

[root@gnuadmin ~]# ls
anaconda-ks.cfg  link  test  wget-1.14-18.el7_6.1.x86_64.rpm

Varsayalım ki, boot sürecinde yaşanan hataları ekibimizle paylaşmak istiyoruz. “/var/log/dmesg” dosyası içinde “error” geçen satırları seçip bunları bir dosyaya alalım. Burada grep komutundan faydalanacağız:

[root@gnuadmin ~]# grep -i error /var/log/dmesg
[    0.644777] BERT: Boot Error Record Table support is disabled. Enable it by using bert_enable as kernel parameter.
[    1.536000] [drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message.
[    1.536927] [drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message.

Çıktılarımız, varsayılan olarak STDOUT’a düştü. Peki bu çıktıları bir dosyaya nasıl yönlendirebiliriz? Cevap: Kopyala-yapıştır yaparız değil tabii… Burada yardımımıza “>” işareti koşar:

[root@gnuadmin ~]# grep -i error /var/log/dmesg > boot_hatalari.txt
[root@gnuadmin ~]# cat boot_hatalari.txt 
[    0.644777] BERT: Boot Error Record Table support is disabled. Enable it by using bert_enable as kernel parameter.
[    1.536000] [drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message.
[    1.536927] [drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message.

Dikkat ettiyseniz, grep komutunun çıktısı ekrana düşmedi. “boot_hatalari.txt” isimli bir dosyaya yazıldı. Dosyayı okuduğumuzda ise, çıktıyı görebiliyoruz.

Bu yönlendirme ile ilgili şunları unutmamalısınız:

  • “>” işareti ile yönlendirme yaptığınız dosya eğer yoksa, oluşturulur.
  • “>” işareti ile yönlendirme yaptığınız dosya zaten mevcutsa, “tüm içeriği silinir ve yönlendirdiğiniz çıktı, dosyanın üzerine yazılır“.
  • Var olan bir dosyanın üzerine “ekleme (append)” yapmak için “>>” işareti kullanılır.

Yukarıdaki senaryoyu şöyle değiştirmeyi deneyelim. Bir dosya içine, önce durumu anlatan ufak bir mesaj yazalım. Sonra error’ları ekleyelim. Son olarak da tarih ve saati ekleyelim ve dosyamızı tamamlayalım:

[root@gnuadmin ~]# echo "Makinede görülen boot hataları" > boot_hatalari.txt 
[root@gnuadmin ~]# grep -i error /var/log/dmesg > boot_hatalari.txt
[root@gnuadmin ~]# date > boot_hatalari.txt 
[root@gnuadmin ~]# cat boot_hatalari.txt 
Paz Ara 26 21:36:34 +03 2021

Yönlendirmeyi yaparken hep “>” işareti kullandık. Bu nedenle en son çıktı hariç kalan her şey silindi. Şimdi dosyayı silelim ve “>” yerine “>>” kullanalım:

[root@gnuadmin ~]# rm boot_hatalari.txt 
rm: normal dosya `boot_hatalari.txt' silinsin mi?y       
[root@gnuadmin ~]# echo "Makinede görülen boot hataları" > boot_hatalari.txt 
[root@gnuadmin ~]# grep -i error /var/log/dmesg >> boot_hatalari.txt
[root@gnuadmin ~]# date >> boot_hatalari.txt 
[root@gnuadmin ~]# cat boot_hatalari.txt 
Makinede görülen boot hataları
[    0.644777] BERT: Boot Error Record Table support is disabled. Enable it by using bert_enable as kernel parameter.
[    1.536000] [drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message.
[    1.536927] [drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message.
Paz Ara 26 21:37:41 +03 2021

Gördüğünüz gibi, verileri kaybetmeden yeni veriler ekleyebildik.

Linux'ta Standard Output (STDOUT) Yönlendirme
Linux’ta Standard Output (STDOUT) Yönlendirme

Standard Error (STDERR, Standart Hata)

STDERR de, tıpkı STDOUT gibi varsayılan olarak terminalinize gönderilir. Bir komut çalıştırdığınızda, komutun hata verdiğini gösteren satırları da terminalinizde görürsünüz. Ancak aslında çıkış noktaları farklıdır.

Şimdi “mkdir” komutu ile birkaç dizin oluşturmayı deneyelim ve çıktıları inceleyelim:

[root@gnuadmin ~]# mkdir muzik
[root@gnuadmin ~]# mkdir muzik/rap muzik/house muzik/trance film/komedi film/aksiyon
mkdir: `film/komedi' dizini oluşturulamıyor: Böyle bir dosya ya da dizin yok
mkdir: `film/aksiyon' dizini oluşturulamıyor: Böyle bir dosya ya da dizin yok

muzik” dizinini oluşturduktan sonra, bu dizin altında 3 yeni dizin daha oluşturmayı deniyoruz. Aynı zamanda, var olmayan “film” dizini altında da 2 alt dizin oluşturmayı deniyoruz ve tabii ki hata ile karşılaşıyoruz.

Şimdi bu hata çıktılarını, bir dosyaya yönlendirmeyi deneyelim. Bunun için “2>” kullanacağız:

[root@gnuadmin ~]# mkdir muzik
[root@gnuadmin ~]# mkdir muzik/rap muzik/house muzik/trance film/komedi film/aksiyon 2> dizin_hatalari
[root@gnuadmin ~]# cat dizin_hatalari 
mkdir: `film/komedi' dizini oluşturulamıyor: Böyle bir dosya ya da dizin yok
mkdir: `film/aksiyon' dizini oluşturulamıyor: Böyle bir dosya ya da dizin yok

Gördüğünüz üzere, komutun hataları ekrana basılmadı. Bunun yerine “dizin_hatalari” isimli bir dosyaya eklendi.

Bu yönlendirme ile ilgili şunları unutmamalısınız:

  • “2>” işareti ile yönlendirme yaptığınız dosya eğer yoksa, oluşturulur.
  • “2>” işareti ile yönlendirme yaptığınız dosya zaten mevcutsa, “tüm içeriği silinir ve yönlendirdiğiniz çıktı, dosyanın üzerine yazılır“.
  • Var olan bir dosyanın üzerine “ekleme (append)” yapmak için “2>>” işareti kullanılır.

STDOUT ve STDERR’i Aynı Anda Yönlendirme

“mkdir” örneğinde, hatalı çıktıların da ekrana geldiğini görmüştük. Burada aklımıza şu soru gelebilir. “>” işaretini kullanarak her şeyi bir dosyaya gönderemez miyiz?

Cevap basit: Hayır. Çünkü bu çıktılar, daha önce de belirttiğimiz gibi, 2 farklı tanımlayıcıdan geliyor. Aşağıdaki örneği inceleyelim:

[root@gnuadmin ~]# mkdir -v muzik
mkdir: dizin `muzik' oluşturuldu
[root@gnuadmin ~]# mkdir -v  muzik/rap muzik/house muzik/trance film/komedi film/aksiyon > mkdir_ciktisi
mkdir: `film/komedi' dizini oluşturulamıyor: Böyle bir dosya ya da dizin yok
mkdir: `film/aksiyon' dizini oluşturulamıyor: Böyle bir dosya ya da dizin yok
[root@gnuadmin ~]# cat mkdir_ciktisi 
mkdir: dizin `muzik/rap' oluşturuldu
mkdir: dizin `muzik/house' oluşturuldu
mkdir: dizin `muzik/trance' oluşturuldu

Örnekte de görüldüğü üzere, başarılı dizin oluşturma işlemlerinin sonucu dosyaya gönderilmiş olmasına rağmen; hatalar ekrana geldi.

Linux’ta hem STDOUT’u hem de STDERR’i aynı anda yönlendirmek için “&>” işaretini kullanırız.

[root@gnuadmin ~]# mkdir -v muzik
mkdir: dizin `muzik' oluşturuldu
[root@gnuadmin ~]# mkdir -v  muzik/rap muzik/house muzik/trance film/komedi film/aksiyon &> mkdir_ciktisi
[root@gnuadmin ~]# cat mkdir_ciktisi 
mkdir: dizin `muzik/rap' oluşturuldu
mkdir: dizin `muzik/house' oluşturuldu
mkdir: dizin `muzik/trance' oluşturuldu
mkdir: `film/komedi' dizini oluşturulamıyor: Böyle bir dosya ya da dizin yok
mkdir: `film/aksiyon' dizini oluşturulamıyor: Böyle bir dosya ya da dizin yok

Bu yönlendirmeyi yaptıktan sonra, ekranda herhangi bir çıktı almadık. Ancak STDOUT ve STDERR birleştirildi ve dosyaya yazıldı.

Linux'ta STDOUT ve STDERR Yönlendirmesi
Linux’ta STDOUT ve STDERR Yönlendirmesi

Bu yönlendirme ile ilgili şunları unutmamalısınız:

  • “&>” işareti ile yönlendirme yaptığınız dosya eğer yoksa, oluşturulur.
  • “&>” işareti ile yönlendirme yaptığınız dosya zaten mevcutsa, “tüm içeriği silinir ve yönlendirdiğiniz çıktı, dosyanın üzerine yazılır“.
  • Var olan bir dosyanın üzerine “ekleme (append)” yapmak için “&>>” işareti kullanılır.

Standard Input (STDIN, Standart Girdi)

Standart girdi, varsayılan olarak klavyeniz ve diğer girdi aygıtlarınızdır.

Bazı durumlarda, komutlarınıza girdi olarak bir dosyayı vermek isteyebilirsiniz. Aşağıdaki örnekte, “sort” programına “/etc/passwd” dosyası girdi olarak verilmiştir. Tabii ki sort programı, zaten bir dosyayı parametre olarak alabilmektedir. Sadece örnek vermeye çalışıyorum 🙂

[root@gnuadmin ~]# sort < /etc/passwd
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
halt:x:7:0:halt:/sbin:/sbin/halt
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin

Burada dikkat etmemiz gereken nokta, gelen çıktının yine STDOUT’ta olması. Yani “/etc/passwd” dosyası üzerinde hiçbir değişiklik yapılmadı. Peki biz bu değiştirilmiş hâli de farklı bir dosyaya yönlendiremez miyiz? Tabii ki yönlendirebiliriz:

[root@gnuadmin ~]# sort < /etc/passwd > sirali_liste
[root@gnuadmin ~]# cat sirali_liste 
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
halt:x:7:0:halt:/sbin:/sbin/halt
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin

Yukarıdaki örnekte, “sort” programına “/etc/passwd” dosyası input olarak verilmiştir ve komutun output’u “sirali_liste” dosyasına yazılmıştır.

Programlar Arasında Çıktı Yönlendirme

Yazının bu noktasına kadar, sadece dosyalarla çalıştık. Peki komutların çıktısını başka bir komuta nasıl gönderebiliriz?

Sistemimizdeki kullanıcıların sıralı, alfabetik bir listesini almak istediğimizi varsayalım. Bunun için “/etc/passwd” dosyasını “:” karakterine göre ayıracağız, ilk sütunu alacağız. Sonrasında bu değerleri, “sort” programına gönderip sıralayacağız. Son olarak sıralı listeyi “nl” programına vereceğiz ve sonucu bir dosyaya yazacağız. İşin güzel tarafı şu, bunları yaparken sadece 1 kez enter’a basmak yeterli olacak:

Bu yönlendirmeyi yapmak için “| (pipe)” işaretini kullanacağız:

[root@gnuadmin ~]# cut -d ":" -f 1 /etc/passwd | sort | nl
     1	adm
     2	bin
     3	daemon
     4	dbus
     5	ftp
     6	games
     7	halt
     8	lp
     9	mail
    10	nobody
    11	operator
    12	polkitd
    13	postfix
    14	root
    15	shutdown
    16	sshd
    17	sync
    18	systemd-network
[root@gnuadmin ~]# cut -d ":" -f 1 /etc/passwd | sort | nl > kullanici_listesi.txt