Ana içeriğe geç

09- 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 gerek loglama, gerekse farklı araçları bir araya getirerek amacınıza ulaşma noktasında oldukça elzemdir.

Çalıştırdığınız komutların çıktılarını gönderdiği noktayı ifade eden dosya tanımlayıcısı (file descriptor) "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:

ali@ubuntu24:~$ ls
evraklar   kopya1   projeler  'tatil fotoğrafları'

Varsayalım ki, bu çıktıyı bir dosyaya yazdırmak istiyoruz. Dosyanın ismi de "dosya_listesi" olsun. Burada yardımımıza ">" işareti koşar:

ali@ubuntu24:~$ ls > dosya_listesi
ali@ubuntu24:~$

Çıktılarımız, bu sefer varsayılan olarak STDOUT'a düşmedi. Fakat artık yeni bir dosyamız var. cat ile okuduğumuzda ise, daha önce gördüğümüz ls çıktısını görüyoruz:

ali@ubuntu24:~$ ls
dosya_listesi   evraklar   kopya1   projeler  'tatil fotoğrafları'
ali@ubuntu24:~$ cat dosya_listesi
dosya_listesi
evraklar
kopya1
projeler
tatil fotoğrafları
ali@ubuntu24:~$

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.

Hatırlarsanız, ekrana çıktı vermemizi sağlayan bir komutumuz vardı, echo. Şimdi bu komutun çıktısını, "dosya_listesi" dosyamıza yönlendirelim ve ne olduğuna bakalım:

ali@ubuntu24:~$ echo standart çıktıdayım
standart çıktıdayım
ali@ubuntu24:~$ echo dosya içine yazılacağım > dosya_listesi
ali@ubuntu24:~$ cat dosya_listesi
dosya içine yazılacağım

İlk başta herhangi bir yönlendirme yapmadık ve çıktımız STDOUT'a yazıldı.

Ekran?

Bu zamana kadar, "çıktıyı ekrana yazdırır" gibi ifadeler kullandık. Aslında bunun teknik karşılığı, STDOUT. Çıktıyı ekranımızda gördüğümüz için, genel kullanımda "ekran" deriz. Fakat artık bunun 1 numaralı descriptor ile tanımlanan STDOUT (Standard Output, Standart Çıktı) olduğunu biliyorsunuz.

Devamında ise ">" karakteri ile yönlendirme yaptık. Dosyamızı tekrar okuduk ve tüm içeriğinin silindiğini, yalnızca "dosya içine yazılacağım" ifadesinin kaldığını gördük. Şimdi ise bu verinin üzerine, ">>" işaretini kullanarak yeni bir veri ekleyelim (append):

ali@ubuntu24:~$ cat dosya_listesi
dosya içine yazılacağım
dosya_listesi
evraklar
kopya1
projeler
tatil fotoğrafları

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

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:

ali@ubuntu24:~$ mkdir muzik
ali@ubuntu24:~$ mkdir muzik/rap muzik/house muzik/trance film/komedi film/aksiyon
mkdir: cannot create directory ‘film/komedi’: No such file or directory
mkdir: cannot create directory ‘film/aksiyon’: No such file or directory

"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. STDERR'nin file descriptor numarasının 2 olduğundan bahsetmiştik. Öncelikle oluşturduğumuz "muzik" dizinini komple silelim ve baştan başlayalım:

ali@ubuntu24:~$ rm -r muzik
ali@ubuntu24:~$ mkdir muzik
ali@ubuntu24:~$ mkdir muzik/rap muzik/house muzik/trance film/komedi film/aksiyon 2> dizin_hatalari
ali@ubuntu24:~$ ls
dizin_hatalari   dosya_listesi   evraklar   kopya1   muzik   projeler  'tatil fotoğrafları'

rm -r muzik ve mkdir muzik komutları, herhangi bir çıktı vermedi. Çünkü herhangi bir sorun yaşamadan işlerini tamamladılar. Üçüncü komutumuz da hiçbir çıktı üretmedi. Çünkü "muzik" altındaki dizinleri başarıyla oluşturdu. "film" ile ilişkili dizinleri oluşturamamasını bekliyorduk. ls ile baktığımızda, oluşmadıklarını da gördük. Fakat "dizin_hatalari" isimli yeni bir dosyamız olduğunu fark ettik.

Bu dosyanın içini okuduğumuzda ise, mkdir programının normalde shell'imize yazacağı hataları, dosyaya yönlendirmiş olduğumuzu göreceğiz:

ali@ubuntu24:~$ cat dizin_hatalari
mkdir: cannot create directory ‘film/komedi’: No such file or directory
mkdir: cannot create directory ‘film/aksiyon’: No such file or directory

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. mkdir -v komutu ile, oluşturulan dizinler hakkında da bilgi verilmesini isteyebiliriz.

Verbose

Linux'ta programların çıktılarını daha detaylı görmek için, çıktıları verbose edebiliriz. Bu sayede, biz komutu çalıştırırken olan biten şeyler hakkında daha fazla bilgi alabiliriz. Kullandığınız komuta göre, verbose opsiyonu değişiklik gösterebilir.

ali@ubuntu24:~$ rm -r muzik
ali@ubuntu24:~$ mkdir -v muzik
mkdir: created directory 'muzik'
ali@ubuntu24:~$ mkdir -v muzik/rap muzik/house muzik/trance film/komedi film/aksiyon > islem_sonucu
mkdir: cannot create directory ‘film/komedi’: No such file or directory
mkdir: cannot create directory ‘film/aksiyon’: No such file or directory
ali@ubuntu24:~$ cat islem_sonucu
mkdir: created directory 'muzik/rap'
mkdir: created directory 'muzik/house'
mkdir: created directory 'muzik/trance'

Neler yaptığımızı inceleyelim:

  • "muzik" dizinini sildik
  • "muzik" dizinini, mkdir -v ile oluşturduk. Oluşturduğuna dair bir mesaj verdi. Bu, bir hata değil. Bir bilgi. İşler yolunda. Bu mesajı görebilmeyi biz istedik. Bu mesaj, bir STDOUT mesajı.
  • "muzik" altına ve "film" altına, yeni dizinler oluşturmak istedik. Fakat ">" karakteri ile, STDOUT'u "islem_sonucu" isimli bir dosyaya yönlendirdik. Burada yine "-v" opsiyonunu kullandık. Yani başarılı işlemlerle ilgili de mesajlar almak istediğimizi belirttik.
  • Komutumuz hata verdi. "film/komedi" ve "film/aksiyon" dizinleri oluşturulamadı. Çünkü "film" diye bir dizin zaten yok. O olmadığı için, alt dizinleri de oluşturulamadı. Bunlar birer hata ve STDERR'e giden mesajlar. Biz, bu çıktıyı bir yere yönlendirmediğimiz için shell'imize geldi. Ancak başarıyla oluşturulan dizinler için bir çıktı göremedik. Çünkü STDOUT mesajlarını, ">" karakteri ile "islem_sonucu" dosyasına yönlendirdik.
  • "islem_sonucu" dosyasını cat ile okuduk. mkdir -v komutunun başarılı sonuçlarının, yani normalde STDOUT'ta olması gereken sonuçlarının, bu dosya içine yazıldığını gördük.

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

ali@ubuntu24:~$ rm -r muzik
ali@ubuntu24:~$ mkdir -v muzik
mkdir: created directory 'muzik'
ali@ubuntu24:~$ mkdir -v muzik/rap muzik/house muzik/trance film/komedi film/aksiyon &> islem_sonucu
ali@ubuntu24:~$ cat islem_sonucu
mkdir: created directory 'muzik/rap'
mkdir: created directory 'muzik/house'
mkdir: created directory 'muzik/trance'
mkdir: cannot create directory ‘film/komedi’: No such file or directory
mkdir: cannot create directory ‘film/aksiyon’: No such file or directory
Yukarıdaki örneğe benzer bir şey yaptık. Fakat farklı olarak, çıktıyı "&>" ile yönlendirdik. mkdir -v komutundan hiçbir çıktı alamadık. Çünkü hem STDOUT hem de STDERR, "&>" sayesinmde "islem_sonucu" dosyasına yönlendirildi.

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.

Çıktıların Ayrılması

Bazen çalıştıracağınız komutun ya da script'in, sadece hataları ile ilgilenirsiniz. Bazen tüm çıktıyı log'lamak isteyebilirsiniz. Bazen başarılı adımları log'layıp, hataların önünüze düşmesini istersiniz. Bu ve bunun gibi durumlar için, çıktıları manipüle edip farklı dosyalara gönderebiliyor olmak önemlidir.

Son olarak aşağıdaki örneği inceleyelim:

ali@ubuntu24:~$ rm -r muzik
ali@ubuntu24:~$ mkdir -v muzik
mkdir: created directory 'muzik'
ali@ubuntu24:~$ mkdir -v muzik/rap muzik/house muzik/trance film/komedi film/aksiyon > basarili 2> basarisiz
ali@ubuntu24:~$ cat basarili
mkdir: created directory 'muzik/rap'
mkdir: created directory 'muzik/house'
mkdir: created directory 'muzik/trance'
ali@ubuntu24:~$ cat basarisiz
mkdir: cannot create directory ‘film/komedi’: No such file or directory
mkdir: cannot create directory ‘film/aksiyon’: No such file or directory

"muzik" dizinini sildik. Tekrar oluşturduk. Bir kısmının sorunsuz, bir kısmının sorunlu olacağını bildiğimiz mkdir komutumuzu yine çalıştırdık. Fakat "> basarili" ifadesi ile STDOUT'u "basarili" dosyasına yönlendirdik. Devamında gelen "2> basarisiz" ile de, STDERR'i "basarisiz" isimli bir dosyaya yönlendirdik. Bu iki dosyayı ayrı ayrı okuduğumuzda, komutumuzun başarılı çalışan ve başarısız olan kısımlarını ayrı ayrı inceleyebildik.

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, cat programına "/etc/passwd" dosyası girdi olarak verilmiştir. Tabii ki cat /etc/passwd şeklinde de kullanabilirdik. Sadece örnek olması açısından böyle bir kullanım tercih ettik.

ali@ubuntu24:~$ cat < /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
systemd-timesync:x:997:997:systemd Time Synchronization:/:/usr/sbin/nologin
dhcpcd:x:100:65534:DHCP Client Daemon,,,:/usr/lib/dhcpcd:/bin/false
messagebus:x:101:102::/nonexistent:/usr/sbin/nologin
systemd-resolve:x:992:992:systemd Resolver:/:/usr/sbin/nologin
pollinate:x:102:1::/var/cache/pollinate:/bin/false
polkitd:x:991:991:User for polkitd:/:/usr/sbin/nologin
syslog:x:103:104::/nonexistent:/usr/sbin/nologin
uuidd:x:104:105::/run/uuidd:/usr/sbin/nologin
tcpdump:x:105:107::/nonexistent:/usr/sbin/nologin
tss:x:106:108:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:107:109::/var/lib/landscape:/usr/sbin/nologin
fwupd-refresh:x:989:989:Firmware update daemon:/var/lib/fwupd:/usr/sbin/nologin
usbmux:x:108:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
ali:x:1000:1000:Ali:/home/ali:/bin/bash
sshd:x:109:65534::/run/sshd:/usr/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:

ali@ubuntu24:~$ cat < /etc/passwd > kullanici_listesi
ali@ubuntu24:~$ cat kullanici_listesi
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
systemd-timesync:x:997:997:systemd Time Synchronization:/:/usr/sbin/nologin
dhcpcd:x:100:65534:DHCP Client Daemon,,,:/usr/lib/dhcpcd:/bin/false
messagebus:x:101:102::/nonexistent:/usr/sbin/nologin
systemd-resolve:x:992:992:systemd Resolver:/:/usr/sbin/nologin
pollinate:x:102:1::/var/cache/pollinate:/bin/false
polkitd:x:991:991:User for polkitd:/:/usr/sbin/nologin
syslog:x:103:104::/nonexistent:/usr/sbin/nologin
uuidd:x:104:105::/run/uuidd:/usr/sbin/nologin
tcpdump:x:105:107::/nonexistent:/usr/sbin/nologin
tss:x:106:108:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:107:109::/var/lib/landscape:/usr/sbin/nologin
fwupd-refresh:x:989:989:Firmware update daemon:/var/lib/fwupd:/usr/sbin/nologin
usbmux:x:108:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
ali:x:1000:1000:Ali:/home/ali:/bin/bash
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
ali@ubuntu24:~$

Yukarıdaki örnekte, cat programına "/etc/passwd" dosyasını input olarak verdik ve komutun output'unu ""kullanici_listesi" dosyasına yönlendirdik.

Programlar Arasında Çıktı Yönlendirme

Şu ana kadar, sadece dosyalarla çalıştık. Peki komutların çıktısını başka bir komuta nasıl gönderebiliriz?

Bu yönlendirmeyi yapmak için "| (pipe)" işaretini kullanacağız. Aşağıdaki örneği inceleyin:

ali@ubuntu24:~$ whatis passwd
passwd (1)           - change user password
passwd (1ssl)        - OpenSSL application commands
passwd (5)           - the password file
ali@ubuntu24:~$ whatis passwd | nl
     1  passwd (1)           - change user password
     2  passwd (1ssl)        - OpenSSL application commands
     3  passwd (5)           - the password file

whatis passwd komutu ile, "passwd" ifadesi hakkında bilgi aldık. whatis, çıktısını STDOUT'a yazdı. Fakat biz bu çıktıyı "|" (Alt Gr (sağ alt) + <, en azından benim klavyemde) karakteri ile nl programına yönlendirdik.

Daha farklı ve anlamlı bir deneme yapalım. Fakat bunun için, henüz detaylarını bilmediğimiz "/etc/passwd" dosyasını kullanacağız ve ileride değineceğimiz cut ve sort gibi komutlar kullanacağız. Yapılacak işi şu şekilde özetleyebiliriz:

  • Sistemde yer alan kullanıcıların alfabetik olarak sıralı hâlini, "alfabetik liste" isimli bir dosyada görmek istiyoruz.
  • Kullanıcı bilgilerini, "/etc/passwd" dosyasının ilk sütunundan alacağız.
  • Bu sütunlar, ":" karakteri ile ayrılmış durumda. Ayrımı yapabilmek için cut programını kullanabiliriz.
  • Çıktıyı, sort programı ile sıralayabiliriz.
  • Sıralanmış çıktıyı, nl programı ile numaralandırabiliriz.
  • Son olarak tüm bu çıktıyı, "alfabetik liste" isimli dosyaya, ">" karakteri ile yönlendirebiliriz.
ali@ubuntu24:~$ cut -d : -f 1 /etc/passwd | sort | nl > "alfabetik liste"
ali@ubuntu24:~$ cat alfabetik\ liste
     1  ali
     2  _apt
     3  backup
     4  bin
     5  daemon
     6  dhcpcd
     7  fwupd-refresh
     8  games
     9  irc
    10  landscape
    11  list
    12  lp
    13  mail
    14  man
    15  messagebus
    16  news
    17  nobody
    18  polkitd
    19  pollinate
    20  proxy
    21  root
    22  sshd
    23  sync
    24  sys
    25  syslog
    26  systemd-network
    27  systemd-resolve
    28  systemd-timesync
    29  tcpdump
    30  tss
    31  usbmux
    32  uucp
    33  uuidd
    34  www-data
ali@ubuntu24:~$

Merak Etmeyin

Bu örnekte kullandığımız araçlara, ilerleyen bölümlerde değineceğiz.

Çıktıların Yönlendirilmesi

Çıktı yönlendirmesi yaparken, özellikle üst üste yönlendirme yapıyorsak, işler zihnimizde canlandırdığımız gibi ilerlemeyebilir. Böyle durumlarda yönlendirmeyi bir kenara bırakıp, çıktıyı ekranda görmek ve doğru ilerlediğimizden emin olarak yönlendirmeye devam etmek faydalı olabilir.