Bu yüzden lesmana gibi bir cevaba katkıda bulunmak istedim, ama benimkinin belki biraz daha basit ve biraz daha avantajlı saf Bourne kabuğu çözümü olduğunu düşünüyorum:
# You want to pipe command1 through command2:
exec 4>&1
exitstatus=`{ { command1; printf $? 1>&3; } | command2 1>&4; } 3>&1`
# $exitstatus now has command1's exit status.
Bence bu en iyi içten dışa açıklanmıştır - command1 stdout'ta (dosya tanımlayıcı 1) normal çıktısını yürütecek ve yazdıracaktır, daha sonra, printf icommand1'in çıkış kodunu stdout'ta yürütecek ve yazacaktır, ancak bu stdout yönlendirilir dosya tanıtıcı 3.
Komut1 çalışırken, stdout'u command2'ye bağlanır (printf'in çıkışı asla command2'ye gönderilmez çünkü pipo'nun okuduğu 1 yerine dosya tanımlayıcı 3'e göndeririz). Daha sonra command2'nin çıktısını dosya tanımlayıcı 4'e yönlendiririz, böylece dosya tanımlayıcı 1'in dışında kalır - çünkü dosya tanımlayıcı 1'in biraz sonra ücretsiz olmasını istiyoruz, çünkü dosya tanımlayıcı 3'teki printf çıktısını dosya tanımlayıcıya geri getireceğiz 1 - çünkü komut ikamesi (backticks), yakalayacak ve değişkene yerleştirilecek olan budur.
Son sihir biti, önce exec 4>&1
ayrı bir komut olarak yaptığımızdır - dosya tanımlayıcı 4'ü dış kabuğun stdout'unun bir kopyası olarak açar. Komut ikamesi, standartta yazılanları içindeki komutların perspektifinden yakalar - ancak komut2'nin çıkışı komut ikamesi söz konusu olduğunda tanımlayıcı 4'e dosyalayacağından, komut ikamesi onu yakalamaz - ancak komut yerine "dışarı" alır hala etkili bir şekilde komut dosyasının genel dosya tanımlayıcı 1 gidiyor.
( exec 4>&1
Ayrı bir komut olması gerekir, çünkü birçok ortak kabuk, bir ikame kullanan "harici" komutta açılan bir komut tanımlayıcısının içindeki bir dosya tanımlayıcısına yazmaya çalıştığınızda hoşunuza gitmez. Bunu yapmanın en basit taşınabilir yolu.)
Komutların çıktıları birbirini atlıyormuş gibi ona daha az teknik ve daha eğlenceli bir şekilde bakabilirsiniz: komut1 komutları komut2'ye atlar, ardından printf'in çıkışı komut 2'nin üzerine atlar, böylece komut2 yakalamaz ve sonra komut 2'nin çıktısı, tıpkı printf değişkenle yakalanacak şekilde ikame tarafından yakalanmak için tam zamanında geldiği gibi komut ikamesinin üstünden ve dışına atlar ve komut2'nin çıktısı, tıpkı normal bir boruda.
Ayrıca, anladığım kadarıyla, $?
borudaki ikinci komutun dönüş kodunu hala içerecektir, çünkü değişken atamaları, komut ikameleri ve bileşik komutların hepsi, içindeki komutun dönüş koduna etkili bir şekilde şeffaftır, bu nedenle command2 yayılmalı - bu ve ek bir işlev tanımlamak zorunda değilim, bu yüzden lesmana tarafından önerilenden biraz daha iyi bir çözüm olabileceğini düşünüyorum.
Uyarılar lesmana'dan bahsetmişken, command1'in bir noktada 3 veya 4 dosya tanımlayıcılarını kullanması mümkündür, böylece daha sağlam olmak için şunları yaparsınız:
exec 4>&1
exitstatus=`{ { command1 3>&-; printf $? 1>&3; } 4>&- | command2 1>&4; } 3>&1`
exec 4>&-
Örneğimde bileşik komutları kullandığımı, ancak alt kabukların ( ( )
bunun yerine kullanmak { }
da işe yarayacağını, ancak belki de daha az verimli olabileceğini) unutmayın.
Komutlar, dosya tanımlayıcılarını, bunları başlatan işlemden devralır, böylece ikinci satırın tamamı dosya tanımlayıcı dörtünü devralır ve ardından bileşik komutu 3>&1
dosya tanımlayıcı üçünü devralır. Böylece, 4>&-
iç bileşik komutunun dosya tanımlayıcı dörtünü 3>&-
devralmayacağından ve dosya tanımlayıcı üçünü devralmayacağından, komut1 'daha temiz', daha standart bir ortam alır. İçini de 4>&-
yanına taşıyabilirsiniz 3>&-
, ama neden sadece kapsamını mümkün olduğunca sınırlamakla kalmayacağını anlıyorum.
Ne sıklıkta şeyler dosya tanımlayıcı üç ve dört doğrudan kullandığınızdan emin değilim - çoğu zaman programların şu anda kullanılmayan dosya tanımlayıcıları döndüren syscalls kullandığını düşünüyorum, ancak bazen kod doğrudan dosya tanımlayıcı 3'e yazar, ben tahmin (Ben bir program açık olup olmadığını görmek için bir dosya tanımlayıcı kontrol ve açıksa onu kullanarak, ya da değilse farklı davranır hayal). Bu nedenle, ikincisi akılda tutmak ve genel amaçlı vakalar için kullanmak en iyisidir.