Şimdiden çok iyi cevapların var. Anlayışını büyük ölçüde yardımcı olan, burada yer alan iki farklı kavram olduğunu vurgulamama izin verin:
Arka plan: Dosya tanımlayıcısı vs. dosya tablosu
Dosya tanımlayıcınız, işleminizdeki dosya tanımlayıcı tablosundaki dizin olan sadece 0 ... n'dir. Kurallara göre, STDIN = 0, STDOUT = 1, STDERR = 2 (buradaki terimlerin STDIN
vb. Sadece bazı programlama dillerinde ve kılavuz sayfalarında kongre tarafından kullanılan semboller / makrolar olduğuna dikkat edin, STDIN adında gerçek bir "nesne" yoktur; Bu tartışmanın amacı, STDIN ise 0, vs.).
Bu dosya tanımlayıcı tablosu kendi içinde asıl dosyanın ne olduğu hakkında herhangi bir bilgi içermez. Bunun yerine, farklı bir dosya tablosuna bir işaretçi içerir; Sonuncusu, gerçek bir fiziksel dosya (veya engelleme aygıtı veya borusu veya Linux'un dosya mekanizması aracılığıyla ele alabileceği başka herhangi bir şey) ve daha fazla bilgi (yani okumak veya yazmak için) hakkında bilgi içerir.
Bu nedenle, kullandığınızda >
veya <
kabuğunuzda, ilgili dosya tanımlayıcısının işaretçisini başka bir şeye işaret etmek için değiştirirsiniz. Sözdizimi, 2>&1
tanımlayıcı 2'yi, 1 puan olan yere işaret eder. > file.txt
sadece file.txt
yazmak için açılır ve STDOUT'un (dosya decsriptor 1) işaret etmesini sağlar.
Başka hedefler de var, örneğin 2>(xxx)
(yani: çalışan yeni bir işlem xxx
oluşturun, bir boru oluşturun, yeni işlemin dosya tanımlayıcısını 0 borunun okuma ucuna bağlayın ve orijinal işlemin dosya tanımlayıcısını 2 bağlantının yazma ucuna bağlayın boru).
Bu, kabuğunuzdan başka bir yazılımdaki "dosya tanıtımı sihri" nin de temelidir. Örneğin, Perl betiğinizde, dup
STDOUT dosya tanımlayıcısını başka (geçici) bir tanesine yerleştirebilir ve ardından STDOUT dosyasını yeni oluşturulan geçici bir dosyaya yeniden açabilirsiniz. Bu noktadan itibaren, kendi Perl betiğinizden tüm STDOUT çıktısı vesystem()
bu betiğin tüm çağrıları bu geçici dosyada sona erecektir. Tamamlandığında, dup
STDOUT'unuzu kaydettiğiniz geçici tanımlayıcıya yeniden yazabilir ve önceden olduğu gibi hazırlayabilirsiniz. Bu arada, bu geçici tanımlayıcıya bile yazabilirsiniz, bu yüzden gerçek STDOUT çıktınız geçici dosyaya giderken, gerçekte gerçek STDOUT (genellikle kullanıcı) öğelerini çıktı alabilirsiniz .
Cevap
Sorunuza yukarıda verilen temel bilgileri uygulamak için:
Kabuk hangi sırayla komutları yürütür ve yeniden yönlendirmeyi yürütür?
Soldan sağa.
<command> > file.txt 2>&1
fork
yeni bir işlem.
file.txt
İşaretçisini açıp dosya tanımlayıcı 1'de (STDOUT) saklayın.
- STDERR'yi (dosya tanımlayıcısı 2) şu anda fd 1'in işaret ettiği yere (ki bu daha önce
file.txt
elbette zaten açık olan) işaretleyin.
exec
<command>
Bu, görünüşe göre stderr'yi önce stdout'a yönlendirir, ardından ortaya çıkan stdout file.txt dosyasına yönlendirilir.
Sadece bir masa olsaydı bu mantıklı olurdu , ama yukarıda açıklandığı gibi iki tane var. Dosya tanımlayıcıları tekrarlı olarak birbirlerine işaret etmiyor, "STDERR'yi STDOUT'a yönlendir" düşünmenin bir anlamı yok. Doğru düşünce "STDERR'nin STDOUT'un işaret ettiği yere gitmesi" dir. STDOUT'u daha sonra değiştirirseniz, STDERR olduğu yerde kalır, STDOUT'da yapılan diğer değişikliklerle birlikte sihirli bir şekilde ilerlemez.