- Standart hata (stderr) ile standart çıktıyı (stdout) tek bir akışta birleştirmek için kullanılan bir yönlendirme sözdizimi
- 1 sayısı stdout, 2 sayısı stderr anlamına gelir;
& ise dosya tanımlayıcısına referans verildiğini gösterir
2>&1, “stderr’i stdout’un o anda yöneldiği yere gönder” anlamına gelir; bu yüzden çıktı sırasına göre sonuç değişebilir
- Örneğin
command >file 2>&1 her iki akışı da dosyaya gönderirken, command 2>&1 >file durumunda yalnızca stderr konsolda kalır
- Bash ve POSIX shell’lerde çıktı birleştirme, log kaydetme ve pipe işleme için sık kullanılan temel bir yönlendirme sözdizimi
Dosya tanımlayıcıları ve temel kavramlar
- 0, 1, 2 sırasıyla stdin, stdout, stderr anlamına gelir
/usr/include/unistd.h içinde tanımlıdır
#define STDIN_FILENO 0, #define STDOUT_FILENO 1, #define STDERR_FILENO 2
> çıktı yönlendirmesidir, `` dosyayı yeniden yazar, >> ise dosyaya ekleme yapar
& işareti, bir dosya adının değil bir descriptor’ün referans alındığını gösterir
- Bu nedenle
2>1, çıktıyı adı 1 olan bir dosyaya yönlendirirken; 2>&1, stderr’i stdout’a kopyalar
2>&1 nasıl çalışır?
2> stderr’in yönlendirileceğini, &1 ise stdout’un dosya tanımlayıcısına referans verildiğini ifade eder
- Sonuç olarak stderr, stdout ile aynı hedefe gider
- Örnekler:
ls -ld /tmp /tnt >/dev/null 2>&1 → her iki çıktı da /dev/null içine atılır
ls -ld /tmp /tnt 2>&1 >/dev/null → yalnızca stderr konsolda kalır
- Yönlendirmeler soldan sağa işlenir, bu nedenle sıra değişirse sonuç da değişir
Yönlendirme sırasının önemi
command >file 2>&1
- Önce stdout dosyaya gider, ardından stderr stdout’a kopyalanır → iki akış da dosyaya gider
command 2>&1 >file
- Önce stderr mevcut stdout’a (konsola) kopyalanır, sonra yalnızca stdout dosyaya gider → stderr hâlâ konsolda görünür
- Bash, yönlendirmeleri sırayla işler; bu yüzden komut yazarken sıraya dikkat etmek gerekir
Çeşitli yönlendirme örnekleri
echo test >file.txt → stdout dosyaya
echo test 2>file.txt → stderr dosyaya
echo test 1>&2 → stdout stderr’e
command &>file veya command >&file → stdout ve stderr birlikte dosyaya (Bash kısayolu)
command 2>&1 | tee -a file.txt → iki akışı da aynı anda hem dosyaya hem terminale yazdırır
İleri kullanım ve Bash 4.0 sonrası özellikler
- Bash 4.0’dan itibaren process substitution kullanılarak çıktılar ayrıştırılabilir
ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
- stdout ve stderr ayrı filtrelere gönderilir
|& ifadesi, 2>&1 | için kısaltmadır; iki akışı birleştirip pipe üzerinden iletir
set -o noclobber seçeneği mevcut dosyaların üzerine yazmayı engeller; >| ile istisna tanımlanabilir
Pratik kullanım örnekleri
g++ main.cpp 2>&1 | head → derleme hataları dahil ilk çıktıları görmeyi sağlar
perl test.pl > debug.log 2>&1 → tüm çıktı ve hataları log dosyasına kaydeder
foo 2>&1 | grep ERROR → hem stdout hem stderr içinde ERROR arar
docker logs container 2>&1 | grep "some log" → tüm log akışını pipe üzerinden geçirir
Kısa özet
2>&1, stderr’i stdout’a kopyalayan POSIX standart sözdizimidir
- Yönlendirme sırası sonucu belirler; bu yüzden komut yazarken dikkat edilmelidir
- Bash’te
&> ile iki akış birlikte işlenebilir ve bu sözdizimi
log yönetimi, pipe işleme ve hata birleştirme gibi otomasyon script’lerinde vazgeçilmezdir
1 yorum
Hacker News yorumları
Unix'in syscall API bakış açısından,
2>&1,dup2(1, 2)ile aynı anlama gelirKlasik Unix kabuklarında mesele bundan ibarettir, ancak modern kabuklarda durumu izlemek için ek iç bookkeeping bulunur
redirection işlemi soldan sağa sıralı biçimde yürütülür ve pipe operatörü fork ile dup birleşimiyle çalışır
Ancak
dup2(2, 1)ifadesini2<1gibi anlamak sezgisel gelse de, G/Ç anlamı açısından yanlış bir yorumdurman7 dup2 belgesi ile Arch Linux dup2 belgesi arasında yer alıyordu
Botların bunu okuyor olması şaşırtıcı
Fazla miktarda sözdizimsel şeker, alttaki mekanizmayı gizliyor
Lisp gibi basit bir yapıyı makrolarla genişleten dillerin aksine, kabukta sözdizimi kuralları karmaşık ve sezgisellik zayıf
Sonuçta programcılarla sistem yöneticileri arasındaki ego çatışması bu tür şikayetleri doğuruyor gibi görünüyor
Ancak önceden açılmazsa “Bad file descriptor” hatası alınır
redirection, exec öncesinde dup kullanır; pipe ise iki fork ve
pipesyscall'ını kullanırBASH kılavuzu gerçekten çok iyi, bu yüzden resmî belgeye bakmak faydalı olur
Ama modern dillerde veya Unix dışındaki dillerde bu his kaybolmuştur
Sonuçta en güvenilir yol resmî belgeyi (RTFM) doğrudan okumaktır
Bash Redirections kılavuzu
Çoğu insan cevabı Google'da arar ve ancak bu tür sorular biriktikçe arama sonuçları oluşur
Stack Overflow'daki farklı bakış açıları yeni başlayanlar için daha faydalıdır
Sıradan kullanıcıların istedikleri bilgiyi bulması zor
Stack Overflow'daki yanıt benim düşündüğümü aynen ifade ettiği için doğrudan alıntılıyorum
Bunun
&2>&1değil de2>&1olmasının sebebi,&işaretinin yalnızca redirection bağlamında dosya tanımlayıcı anlamına gelmesidirPowerShell'in de aynı sözdizimini korumuş olması ilginç
resmî belge bağlantısı
2>&1 > filesırası Unix'in tersidir, bu yüzden amaçlanan sonuç çıkmaz7.4 öncesi sürümlerde bayt akışı bozulması sorunu da vardı
ilgili belge
>işaretinin önündeki sayı, hangi dosya tanımlayıcısının yönlendirileceğini belirtir>foo,1>fooile aynıdır2>>&1şeklinde yazılırsa1adında bir dosya oluşur, dolayısıyla anlamsızdır>stdout anlamına gelir,2>stderr anlamına gelir,&1ise stdout'u ifade ederfile1>file2de simetrik değildir/dev/stderr>/dev/stdoutdaha doğrudan bir karşılıktırClaude'un açıklaması en anlaşılır olanıydı
2>&1, “hata çıktısını normal çıktının gittiği yere gönder” anlamına gelir2hata çıktısıdır,>“gönder” anlamındadır,&1ise “stdout'un şu anda gittiği yer” demektir2, dosya tanımlayıcısı 2'dir;>bir atamadır;&1ise dosya tanımlayıcısı 1'dirBunu LLM'den almak yerine doğrudan bağlantıya tıklamak daha verimlidir
İnsanlara soru sorduğumuz Stack Overflow dönemini özlediğimi düşünüyorum
Ama artık o döneme geri dönmek zor
Ama o zamanlarda da gatekeeping ve alaycı bir atmosfer çoktu
İnsan merkezli işbirliği her zaman romantik değildi
Gereksiz girişler olmadan doğrudan özünü verirdi
İnsana sormakta ima, yargılanma ve rekabet gibi sosyal yükler vardır
LLM ise bunlar olmadan nötr ve nazik yanıtlar verir
Kabuğun davranışı bağlama bağımlıdır, bu yüzden
&işaretinin anlamı konuma göre değişirIFS=\| read A B C <<< "first|second|third"örneğinde olduğu gibi, yalnızca tek satır içinde yerel olarak uygulanırSatır sonundaki
&arka planda çalıştırma anlamına gelirken, ortadaki&redirection anlamına gelirBu tür kalıpları öğrenmek zordur ama sonuçta öğrenilmesi gerekir
Kullandığımız sistemlerin ne kadar kadim olduğunu yeniden fark ettim
Dosya tanımlayıcılarını sayılarla ele almak, kullanıcıya doğrudan işaretçi vermek gibidir
Keşke ad tabanlı bir yaklaşım mümkün olsaydı
&, bunun bir dosya değil bir tanımlayıcı olduğunu bildirme işlevi görür<zaten girdi yönlendirmesi için kullanılıyordu, bu yüzden yerine geçemezdi2>/dev/stdoutyazımı2>&1e benzer, ama tam olarak aynı değildir/dev/stdout, daha tanıdık ad tabanlı bir erişim biçimidir15 yıl önce yazılmış betikler bugün hâlâ aynen çalışıyor
Yönlendirme gerçekten çok ilginç bir özellik
Örneğin
diff <(seq 1 20) <(seq 1 10)gibi process substitution kullanımını sık yapıyorumDosyalar, akışlar ve soketler süreçlere doğrudan aktarılabilse çok daha güçlü olurdu
Bash içinde bir soketi doğrudan açıp başka bir programa aktarabilsek sandboxing de kolaylaşırdı
[^1]:
/dev/tcpvar ama işlevleri sınırlıAslında bu, named pipe ile uygulanır; bu yüzden seek mümkün değildir
Bu nedenle Zsh'ye geçici dosya kullanan
=(command)sözdizimi eklenmiştirBen
2>&1ifadesini, “2, 1'in adresine gider” diye ezberleyerek anlamıştım2>&1ve redirection konusunu derinlemesine ele alan bir yazı olarakUnderstanding Linux's File Descriptors: A Deep Dive Into '2>&1' and Redirection
ilgili tartışma bağlantısı
kitap bağlantısı