DÜZENLEME: Raydan çıktığımı ve sorulandan farklı bir soruyu yanıtladığımı görüyorum. Gerçek sorunun cevabı, Paul Tomblin'in cevabının altında. (Stdout ve stderr'i herhangi bir nedenle ayrı ayrı yönlendirmek için bu çözümü geliştirmek istiyorsanız, burada anlattığım tekniği kullanabilirsiniz.)
Standart çıkış ve stderr arasındaki ayrımı koruyan bir cevap bekliyordum. Ne yazık ki, bu ayrımı koruyan şimdiye kadar verilen yanıtların tümü yarışa yatkındır: yorumlarda belirttiğim gibi, programların eksik girdi görme riskini alıyorlar.
Sanırım sonunda ayrımı koruyan, yarışa yatkın olmayan ve çok da zor olmayan bir cevap buldum.
İlk yapı taşı: stdout ve stderr'i değiştirmek için:
my_command 3>&1 1>&2 2>&3-
İkinci yapı bloğu: Sadece stderr'i filtrelemek isteseydik (örneğin tee), bunu stdout ve stderr'i değiştirerek, filtreleyerek ve sonra geri değiştirerek başarabilirdik:
{ my_command 3>&1 1>&2 2>&3- | stderr_filter;} 3>&1 1>&2 2>&3-
Şimdi gerisi kolay: başlangıçta bir standart çıkış filtresi ekleyebiliriz:
{ { my_command | stdout_filter;} 3>&1 1>&2 2>&3- | stderr_filter;} 3>&1 1>&2 2>&3-
veya sonunda:
{ my_command 3>&1 1>&2 2>&3- | stderr_filter;} 3>&1 1>&2 2>&3- | stdout_filter
Kendimi yukarıdaki komutların her ikisinin de işe yaradığına ikna etmek için aşağıdakileri kullandım:
alias my_command='{ echo "to stdout"; echo "to stderr" >&2;}'
alias stdout_filter='{ sleep 1; sed -u "s/^/teed stdout: /" | tee stdout.txt;}'
alias stderr_filter='{ sleep 2; sed -u "s/^/teed stderr: /" | tee stderr.txt;}'
Çıktı:
...(1 second pause)...
teed stdout: to stdout
...(another 1 second pause)...
teed stderr: to stderr
ve teed stderr: to stderr
beklendiği gibi " " öğesinin hemen ardından istemim geri geliyor .
Zsh hakkında dipnot :
Yukarıdaki çözüm bash'de çalışıyor (ve belki başka kabuklarda, emin değilim), ancak zsh'de çalışmıyor. Zsh'da başarısız olmasının iki nedeni vardır:
- sözdizimi
2>&3-
zsh tarafından anlaşılmaz; yeniden yazılması gerekiyor2>&3 3>&-
- zsh'da (diğer kabukların aksine), zaten açık olan bir dosya tanımlayıcısını yeniden yönlendirirseniz, bazı durumlarda (nasıl karar verdiğini tam olarak anlamıyorum) bunun yerine yerleşik bir tee benzeri davranış yapar. Bundan kaçınmak için, yeniden yönlendirmeden önce her fd'yi kapatmanız gerekir.
Yani, örneğin, ikinci çözümümün zsh olarak yeniden yazılması gerekiyor {my_command 3>&1 1>&- 1>&2 2>&- 2>&3 3>&- | stderr_filter;} 3>&1 1>&- 1>&2 2>&- 2>&3 3>&- | stdout_filter
(ki bu da bash'da çalışıyor, ancak çok ayrıntılı).
Öte yandan, hiç te çalıştırmayan zsh için çok daha kısa bir çözüm elde etmek için zsh'nin gizemli yerleşik örtülü vuruşundan yararlanabilirsiniz:
my_command >&1 >stdout.txt 2>&2 2>stderr.txt
(Bulduğum belgelerden zsh'nin örtük vuruşunu tetikleyen şeyin >&1
ve olduğunu tahmin edemezdim 2>&2
; Bunu deneme yanılma yoluyla buldum.)