Bash'te yönlendirme, bir komutun okuyup yazdığı akışları komut çalışmadan önce dosyalara veya başka akışlara bağlamaktır. En sık kullanılanlar şunlardır: > çıktıyı dosyaya yazar ve dosyayı önce sıfırlar, >> sonuna ekler, < dosyayı girdi yapar, 2> hata akışını ayırır, 2>&1 hata akışını o anda çıktının gittiği yere bağlar, &> ise ikisini birden aynı dosyaya gönderir. Yönlendirmeler soldan sağa işlenir; bu yüzden komut > dosya 2>&1 ile komut 2>&1 > dosya aynı şey değildir.
Bu yazıda GNU Bash kılavuzunun Redirections bölümünün ilk beş alt başlığını (girdi, çıktı, ekleme, stdout ile stderr'i birlikte yönlendirme ve birlikte ekleme) her biri için çalıştırılmış örneklerle anlatıyoruz. Yanlış sırayla yazılmış 2>&1, kendi kendini silen dosya, boş değişkenle yapılan yönlendirme ve noclobber ile dosya koruma gibi pratikte en çok karşılaşılan durumlara da ayrıca değiniyoruz. Here document, dosya tanımlayıcısı açma ve exec ile kalıcı yönlendirme ayrı yazıların konusu; ilgili yerlerde bağlantı veriyoruz.
Üç standart akış: 0, 1 ve 2

Kabukta çalışan her komut üç açık akışla başlar. Kılavuz bunları numaralarıyla anar: standart girdi 0 numaralı dosya tanımlayıcısıdır, standart çıktı 1, standart hata ise 2. Bir komut normal sonuçlarını 1 numaraya, uyarı ve hata mesajlarını 2 numaraya yazar. Terminalde ikisi de aynı ekrana düştüğü için fark edilmez, ama yönlendirme yaptığınız anda ayrışırlar: komut > dosya yalnızca 1 numarayı dosyaya taşır, hata mesajları ekranda kalmaya devam eder.
Operatörün önüne sayı yazmazsanız kılavuzdaki kural devreye girer: operatör < ile başlıyorsa varsayılan tanımlayıcı 0, > ile başlıyorsa 1 kabul edilir. Yani > dosya aslında 1> dosya demektir, < dosya da 0< dosya. Sayıyı açıkça yazdığınızda (2> hata.log) istediğiniz akışı seçersiniz. Sayı ile operatör arasında boşluk olmamalıdır; 2 > dosya yazarsanız 2 komuta sıradan bir argüman olarak gider ve yalnızca standart çıktı yönlenir.
| Operatör | Ne yapar | Dosya varsa |
|---|---|---|
| komut < dosya | dosyayı standart girdiye (0) bağlar | okur |
| komut > dosya | standart çıktıyı (1) dosyaya yazar | önce sıfırlar |
| komut >> dosya | standart çıktıyı dosyanın sonuna ekler | korur, sona ekler |
| komut 2> dosya | standart hatayı (2) dosyaya yazar | önce sıfırlar |
| komut > dosya 2>&1 | iki akışı aynı dosyaya yazar | önce sıfırlar |
| komut &> dosya | yukarıdakinin kısa yazımı | önce sıfırlar |
| komut &>> dosya | iki akışı sona ekler | korur, sona ekler |
| komut >| dosya | noclobber açıkken bile üzerine yazar | önce sıfırlar |
Çıktıyı dosyaya yazmak ve sona eklemek
> hedef dosya yoksa onu oluşturur, varsa boyunu sıfıra indirir ve baştan yazar. >> ise dosya yoksa oluşturur, varsa mevcut içeriğe dokunmadan sona ekler. Günlük (log) tutan betiklerde neredeyse her zaman >> istenir; tek seferlik rapor üreten betiklerde > daha doğrudur. Girdi yönlendirmesi < de dosyayı okumak için açar ve komutun standart girdisine bağlar. Aşağıdaki örnekte wc -l dosya adını argüman olarak değil standart girdi üzerinden aldığı için çıktıda yalnızca sayı görünür; wc -l not.txt yazsaydınız sayının yanında dosya adı da basılırdı.
echo "birinci satır" > not.txt
echo "ikinci satır" >> not.txt
cat not.txt
# çıktı:
# birinci satır
# ikinci satır
wc -l < not.txt
# çıktı: 2
echo "yeni içerik" > not.txt
cat not.txt
# çıktı: yeni içerikSon satırda dikkat edin: üçüncü echo tek > kullandığı için ilk iki satır kayboldu. Bu, yönlendirmenin komut çalışmadan önce yapıldığını da gösterir. Kabuk önce dosyayı açıp sıfırlar, sonra echo çalışır. Komut hiçbir şey yazmasa, hatta bulunamasa bile dosya boşaltılmış olur.
Hata akışını ayırmak: 2>
Bir betiğin ürettiği veriyi bir dosyaya, hata mesajlarını başka bir dosyaya toplamak istediğinizde iki ayrı yönlendirme yazarsınız. Örnekte kendi küçük fonksiyonumuz f bir satırı standart çıktıya, bir satırı >&2 ile standart hataya yazıyor. Bu fonksiyonu yazının devamında da kullanacağız, çünkü iki akışın nereye gittiğini tek bakışta gösteriyor.
f() {
echo "normal çıktı"
echo "hata mesajı" >&2
}
f > cikti.txt 2> hata.txt
echo "cikti.txt: $(cat cikti.txt)"
echo "hata.txt: $(cat hata.txt)"
# çıktı:
# cikti.txt: normal çıktı
# hata.txt: hata mesajıKendi betiklerinizde de aynı ayrımı yapmanız iyi bir alışkanlıktır: kullanıcıya ya da başka bir programa veri olarak gidecek satırlar standart çıktıya, uyarılar ve hatalar standart hataya. Böylece betiğinizin çıktısını bir dosyaya veya boruya bağlayan biri, hata mesajlarının veriye karışmasından korunur. Bunun için genellikle küçük bir yardımcı fonksiyon yazılır:
hata() {
echo "HATA: $*" >&2
}
hata "ayar dosyası bulunamadı" 2> kayit.txt
echo "kayıt: $(cat kayit.txt)"
# çıktı: kayıt: HATA: ayar dosyası bulunamadıYönlendirme sırası neden önemli

Kılavuzun özellikle vurguladığı nokta, yönlendirmelerin yazıldıkları sırayla, soldan sağa işlendiğidir. 2>&1 ifadesi "hata akışını standart çıktıya bağla" diye okunsa da gerçekte yaptığı şey, 2 numaralı tanımlayıcıyı 1 numaranın o anda gösterdiği yerin bir kopyası yapmaktır. Bağlantı kalıcı bir eşleme değildir; o anın fotoğrafıdır.
f > a.txt 2>&1: önce 1 numaraa.txtdosyasına bağlanır, ardından 2 numara 1 numaranın kopyası yapılır. 1 zatena.txtolduğu için ikisi de dosyaya gider.f 2>&1 > b.txt: önce 2 numara 1 numaranın kopyası yapılır; o anda 1 numara terminaldir, dolayısıyla hata akışı terminale bağlanır. Sonra 1 numarab.txtdosyasına taşınır. Hata akışı bu değişiklikten etkilenmez ve ekranda kalır.
f() { echo "normal çıktı"; echo "hata mesajı" >&2; }
f > a.txt 2>&1
echo "--- a.txt"; cat a.txt
f 2>&1 > b.txt
echo "--- b.txt"; cat b.txt
# çıktı:
# --- a.txt
# normal çıktı
# hata mesajı
# hata mesajı
# --- b.txt
# normal çıktıÇıktıdaki dördüncü satır, ikinci çağrının ekrana düşen hata mesajıdır; b.txt dosyasında yalnızca normal çıktı vardır. "Her şeyi dosyaya yazmak istiyorum" diyorsanız kural basit: önce dosyayı, sonra 2>&1 kısmını yazın. Aynı mantık borularda da geçerlidir ve komut 2>&1 > /dev/null | başka_komut gibi bilinçli bir sıra, yalnızca hata akışını boruya aktarmanın bilinen yoludur. Bu konuyu pipe, PIPESTATUS ve pipefail yazısında örnekle gösteriyoruz.
İki akışı birlikte yönlendirmek: &> ve &>>
Bash, "standart çıktı ve standart hatayı aynı dosyaya" işi için kısa bir yazım sunar: &> dosya. Kılavuza göre bu, > dosya 2>&1 ile anlam olarak aynıdır. Eklemeli hali &>> dosya ise >> dosya 2>&1 ile aynıdır. Kılavuz bir de >&dosya biçiminden söz eder ve iki biçimden ilkinin tercih edilmesini önerir; ikinci biçimde dosya adı bir sayıya veya - işaretine genişlerse Bash bunu tanımlayıcı kopyalama olarak yorumlar ve beklenmedik bir sonuç alırsınız.
f() { echo "normal çıktı"; echo "hata mesajı" >&2; }
f &> hepsi.txt
f &>> hepsi.txt
cat hepsi.txt
# çıktı:
# normal çıktı
# hata mesajı
# normal çıktı
# hata mesajıHangi biçimi seçeceğiniz biraz da betiğin hangi kabukta çalışacağıyla ilgilidir. &> bir Bash eklentisidir; #!/bin/sh ile başlayan ve başka bir POSIX kabuğunda çalışabilecek betiklerde uzun biçimi (> dosya 2>&1) kullanmak daha güvenlidir. Bash ile sh arasındaki diğer farklar için Bash ve sh farkı yazısına bakabilirsiniz.
/dev/null ve özel dosya adları
/dev/null yazılan her şeyi yutan, okunduğunda hemen dosya sonu döndüren özel bir dosyadır. Bir komutun yalnızca çıkış durumu ilginizi çekiyorsa ve ekranı kirletmesini istemiyorsanız çıktısını buraya gönderirsiniz. Aşağıdaki örnekte ilk satır yalnızca standart çıktıyı susturur, bu yüzden hata mesajı yine görünür. İkinci satır &> ile ikisini birden susturur. Üçüncü kısım, bir programın kurulu olup olmadığını sessizce sınamanın yaygın bir yoludur: command -v yerleşik komutu bulduğu yolu yazar, biz o yazıyı atıp yalnızca başarılı olup olmadığına bakarız.
f() { echo "normal çıktı"; echo "hata mesajı" >&2; }
f > /dev/null
# çıktı: hata mesajı
f &> /dev/null
echo "sessiz çalıştı, durum: $?"
# çıktı: sessiz çalıştı, durum: 0
if command -v bash > /dev/null; then
echo "bash bulundu"
fi
# çıktı: bash bulunduKılavuz yönlendirmelerde özel muamele gören birkaç dosya adı daha listeler: /dev/stdin, /dev/stdout ve /dev/stderr sırasıyla 0, 1 ve 2 numaralı tanımlayıcıları kopyalar; /dev/fd/N ise N numaralı tanımlayıcıyı kopyalar. İşletim sistemi bu dosyaları sağlıyorsa Bash onları kullanır, sağlamıyorsa aynı davranışı kendi içinde taklit eder. Listede /dev/tcp/host/port ve /dev/udp/host/port biçimleri de vardır; bunlarla Bash bir ağ soketi açmayı dener. Ağ bağlantısı bu yazının kapsamında değil, yalnızca böyle bir özelliğin bulunduğunu bilmeniz yeterli. Taşınabilir betiklerde hata akışına yazmak için /dev/stderr yerine >&2 kullanmanızı öneririz: ikisi aynı işi görür ama >&2 hiçbir özel dosyaya ihtiyaç duymaz.
Yönlendirme komutun neresinde durabilir
Kılavuza göre yönlendirme operatörleri basit bir komutun önünde, içinde herhangi bir yerde ya da sonunda yer alabilir. Kabuk önce yönlendirmeleri ayıklar, kalan sözcükler komut ve argümanları oluşturur. Aşağıdaki örnekte > yer.txt komutun başında duruyor, ikinci satırda ise argümanların arasına girmiş. İkisi de geçerlidir; okunabilirlik için yine de yönlendirmeyi sona yazmak en yaygın tercihtir.
> yer.txt echo merhaba
cat yer.txt
# çıktı: merhaba
echo bir > yer.txt iki üç
cat yer.txt
# çıktı: bir iki üçYönlendirme bileşik komutlara da uygulanabilir. Süslü parantezle gruplanmış komutların ya da bir döngünün tamamını tek bir dosyaya göndermek, her satıra ayrı ayrı >> yazmaktan hem daha kısa hem daha verimlidir; çünkü dosya bir kez açılır. Gruplama ile alt kabuk arasındaki fark için subshell ve çalışma ortamı yazısına, döngüler için for döngüsü ve while döngüsü yazılarına bakabilirsiniz.
{
echo "rapor başlığı"
echo "satır 1"
} > grup.txt
for i in 1 2 3; do
echo "kayıt $i"
done > dongu.txt
cat grup.txt dongu.txt
# çıktı:
# rapor başlığı
# satır 1
# kayıt 1
# kayıt 2
# kayıt 3noclobber ile dosyaları korumak
Yanlışlıkla > yazıp önemli bir dosyanın içeriğini silmek sık yaşanan bir kazadır. set -o noclobber (kısa hali set -C) bu riski azaltır: açıkken > operatörü var olan sıradan bir dosyanın üzerine yazmayı reddeder ve yönlendirme başarısız olur. Bilinçli olarak üzerine yazmak istediğinizde >| operatörünü kullanırsınız; kılavuza göre >| noclobber ayarına bakmadan yönlendirmeyi dener. >> ile sona ekleme noclobber'dan etkilenmez.
echo "ilk" > koru.txt
set -o noclobber
echo "ikinci" > koru.txt
echo "durum: $?"
echo "üçüncü" >| koru.txt
cat koru.txt
set +o noclobber
# çıktı:
# ornek.sh: line 3: koru.txt: cannot overwrite existing file
# durum: 1
# üçüncüHata mesajındaki biçime dikkat edin: Bash betik adını, satır numarasını ve dosya adını yazar, komut çalıştırılmaz ve çıkış durumu 1 olur. Betik ise durmaz, bir sonraki satırla devam eder; betiğin ilk hatada durmasını istiyorsanız set -euo pipefail yazısına bakın. noclobber'ı etkileşimli kabukta açmak isterseniz satırı başlangıç dosyanıza eklersiniz; bunun için .bashrc ve .bash_profile farkı yazısı yol gösterir. Diğer set seçenekleri ile shopt farkı da shopt seçenekleri yazısında anlatılıyor.
Sık yapılan hatalar

Aynı dosyayı hem okuyup hem yazmak
sort liste.txt > liste.txt gibi bir satır listeyi sıralamaz, siler. Sebep yine sıralamadır: kabuk > liste.txt yönlendirmesini komut çalışmadan önce yapar ve dosyayı sıfırlar; komut okumaya başladığında ortada okunacak veri kalmamıştır. Aşağıda zararsız bir cat ile aynı durumu gösteriyoruz. Doğru yol, sonucu önce geçici bir dosyaya yazıp ardından onu asıl dosyanın yerine taşımaktır.
printf '%s\n' kiraz elma armut > liste.txt
cat liste.txt > liste.txt
wc -c < liste.txt
# çıktı: 0Boşluk içeren veya boş değişkene yönlendirmek
Kılavuz, yönlendirme operatöründen sonra gelen sözcüğün genişletildiğini ve birden fazla sözcüğe dönüşürse Bash'in hata verdiğini söyler. Tırnaksız $hedef içinde boşluk varsa sözcük bölme onu iki parçaya ayırır ve "ambiguous redirect" hatası alırsınız. Değişken boşsa da aynı hata gelir, çünkü ortada dosya adı kalmaz. Çözüm her zaman aynıdır: yönlendirme hedefindeki değişkeni çift tırnağa alın. Tırnakların genel kuralları için tek tırnak ve çift tırnak farkı yazısına bakabilirsiniz.
hedef="rapor dosyası.txt"
echo "deneme" > $hedef
# çıktı: ornek.sh: line 2: $hedef: ambiguous redirect
bos=""
echo "deneme" > $bos
# çıktı: ornek.sh: line 5: $bos: ambiguous redirect
echo "deneme" > "$hedef"
cat "$hedef"
# çıktı: denemeSayı ile operatör arasına boşluk koymak
komut 2 > hata.log yazdığınızda Bash 2 sayısını yönlendirmenin parçası saymaz; onu komutun argümanı yapar ve standart çıktıyı hata.log dosyasına gönderir. Tanımlayıcı numarası operatöre bitişik yazılmalıdır: 2> hata.log ya da 2>hata.log. Operatörden sonraki boşluk ise serbesttir.
Her şeyi /dev/null'a atmak
&> /dev/null pratik görünse de hata mesajlarını da yok eder. Bir komut sessizce başarısız olduğunda neden başarısız olduğunu öğrenmenin yolu kalmaz. Gerçekten yalnızca çıkış durumuna bakıyorsanız sorun yok; aksi halde yalnızca standart çıktıyı susturup hataları görünür bırakmak (> /dev/null) ya da hataları bir günlük dosyasına yazmak (2>> hata.log) daha sağlıklıdır. Çıkış durumlarının anlamı için exit kodları yazısına göz atın.
Kısa uygulama: rapor ve hata günlüğü ayrı dosyalarda
Öğrendiklerimizi birleştirelim. Bir bakım betiğinin ürettiği raporun her çalıştırmada yeniden yazılmasını, hataların ise birikerek tek bir günlükte toplanmasını istediğinizi düşünün. Betiğin gövdesini süslü parantezle gruplayıp tek bir satırla iki ayrı hedef verebilirsiniz: { ...; } > rapor.txt 2>> hata.log. Grup içindeki her komutun standart çıktısı rapora gider ve rapor her çalıştırmada sıfırlanır; hata mesajları ise hata.log dosyasının sonuna eklenir. Gruplamanın alt kabuk açmadığını, dolayısıyla grup içinde atanan değişkenlerin dışarıda da geçerli olduğunu hatırlayın.
Bütün betiğin çıktısını en baştan bir dosyaya yönlendirmek istiyorsanız her komutu tek tek değiştirmeniz gerekmez. exec yerleşik komutuna komut vermeden yalnızca yönlendirme yazdığınızda yönlendirme mevcut kabuğa kalıcı olarak uygulanır. Bu teknik, yeni dosya tanımlayıcıları açmak ve eski akışları geri yüklemekle birlikte dosya tanımlayıcıları ve exec yazısında anlatılıyor. Çok satırlı metni bir komuta girdi olarak vermek için here document ve here string yazısına, bir komutun çıktısını dosya adı gibi kullanmak için process substitution yazısına bakabilirsiniz.
Sık Sorulan Sorular
2>&1 ile &> arasında fark var mı?
Bash içinde komut &> dosya ile komut > dosya 2>&1 aynı sonucu verir; kılavuz ikisini anlamca eş sayar. Fark taşınabilirliktedir: &> Bash'e özgüdür, uzun biçim POSIX kabuklarının hepsinde çalışır. 2>&1 tek başına ise yalnızca hata akışını o anki standart çıktıya bağlar; dosyaya yazmak için ondan önce > dosya gerekir.
Hem ekranda görmek hem dosyaya yazmak mümkün mü?
Yönlendirme bir akışı tek bir yere bağlar, bu yüzden tek başına yetmez. Bunun için çıktıyı bir boruyla tee gibi harici bir programa verirsiniz; tee aldığını hem dosyaya hem standart çıktıya yazar. Boru kullanımının ayrıntıları pipe yazısında, tee ile süreç ikamesini birlikte kullanan bir örnek ise process substitution yazısında var.
Neden betiğim cron altında çalışınca çıktı göremiyorum?
Zamanlanmış görevlerde terminal yoktur; çıktının nereye gideceğini görev tanımı belirler. Betiğinizi cron ile çalıştırırken satırın sonuna >> /yol/gorev.log 2>&1 eklemek, hem çıktıyı hem hataları kalıcı bir günlükte toplamanın en basit yoludur. Burada da sıra önemlidir: önce dosya, sonra 2>&1.
noclobber açıkken >> çalışır mı?
Evet. noclobber yalnızca var olan sıradan bir dosyanın > ile sıfırlanmasını engeller. Sona ekleyen >> ve bilerek üzerine yazan >| operatörleri etkilenmez.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Bash öğrenme rehberi · Here document ve here string · Pipe, PIPESTATUS ve pipefail · Dosya tanımlayıcıları ve exec · Process substitution · Linux sunucu komutları