2011-06-23 111 views
3

我想運行一個程序「A」,將其輸出轉到另一個程序「B」的輸入,以及將stdin轉到輸入「B」。如果程序「A」關閉,我想「B」繼續運行。將stdin _and_ stdout重定向到管道

我可以輕鬆地將輸出重定向到B輸入:
./a | ./b

而且,如果我願意,我可以將stderr組合成輸出:
./a 2> & 1 | ./b

但我無法弄清楚如何將stdin合併到輸出中。我的猜測是:
./a 0> & 1 | ./b
但它不起作用。

下面是一個並不需要我們重新編寫了所有的測試程序測試:

$ echo ls 0>&1 | /bin/sh -i 
$ a b info.txt 
$ 
/bin/sh: Cannot set tty process group (No such process) 

如果可能的話,我想這樣做在命令行中使用這個唯一的bash重定向(我不知道想要編寫一個C程序來分離子進程,並且每次我想要將stdin重定向到管道時執行任何複雜的操作)。

+0

也許'tee'命令會幫助你。祝你好運。 – shellter

+0

正如我想到的,@markie,我想知道你在做什麼。這是一個源腳本(例如'。〜/ script.sh')會做你想要的嗎? –

+0

@Arthur這是在玩一個Linux編程遊戲時出現的。 http://www.overthewire.org/wargames/vortex/我還沒有做到這一點,但迄今爲止兩個層面都遇到了這個問題。基本上,如果你給程序一個正確的值,它使用exec()或類似的東西給你一個shell「/ bin/sh -i」。出於某種原因,bash的行爲非常奇怪,其輸入重定向如此。如果在我付出更多努力之前耗盡了輸入,它會變得很奇怪,這導致了笨重的黑客http://axtaxt.wordpress.com/2010/12/28/overthewire-vortex-level10-2/我有一個感覺我們缺少一個明顯的解決方案。 – markie

回答

1

管道有兩端。一個是寫作,而另一個寫的是出現在閱讀的另一端。

這是一個管道,而不是T或Y接頭。

我不認爲你的情況是可能的。讓「stdin去輸入」任何東西都沒有意義。

+0

我能夠將stdout和stderr連接到管道沒有問題,所以可能會有多個附加的東西。就像你可以將多個東西重定向到同一個文件一樣。我不明白你爲什麼抱怨「stdin要輸入」。也許我的英語不好。當我運行「貓」時,stdin將進入貓的輸入。這是否解釋了我的意思是「stdin輸入」更好?現在我想讓stdin從一個管道出來,連接到一個程序的輸入。 – markie

3

如果不編寫一個輔助程序,這是無法完成的。

一般來說,標準輸入可能是一個只讀文件描述符(這可能指的是隻讀文件)。所以你不能「插入」任何東西。

您需要編寫一個「助手」程序來監視兩個文件描述符(比如0和3),以便從兩者中讀取並「合併」它們。一個簡單的selectpoll循環就足夠了,你可以用大多數腳本語言編寫它,但不是shell,我不這麼認爲。

然後,您可以使用shell重定向將您的程序輸出提供給「助手」的描述符3。

既然你想要的東西基本上是「三通」的對面,我可以稱之爲「EET」 ......

[編輯]

只要你能在後臺啓動「貓」。 ..

但是,這將失敗,因爲與控制終端的後臺進程無法從標準輸入讀取。所以,如果你可以從它的控制終端上分離「cat」並在後臺運行它...

在Linux上,「setsid cat」應該大致做到這一點。但是(a)我不能很好地工作,並且(b)我今天真的沒有時間,而且(c)反正它是非標準的。

我只會寫助手程序。

[編輯2]

OK,這似乎工作:

{ seq 5 ; sleep 2 ; seq 5 ; } | /bin/bash -c 'set -m ; setsid cat ; echo HELLO' 

set -m事情力量bash,使作業控制,這顯然是需要防止外殼從/ dev重定向標準輸入/空值。

在這裏,echo HELLO代表您的「程序A」。 seq命令(中間的sleep)只是提供一些輸入。是的,你可以管這整個事情處理B.

關於醜陋和非便攜式解決方案,你可以問...

+0

我不認爲即使背景'貓'會同時讀取多個描述符*。 (如果它不需要同時進行,根據我的答案,前景使用就可以做到這一點)。我希望'socat'有一些有用的東西,但事實並非如此。 –

+0

@Arthur:對,但在後臺運行「cat」將標準輸出複製到stdout中,腳本可以繼續將其自己的數據寫入標準輸出或運行一個子進程。 – Nemo

+0

我看到..使用cat來輸入stdin並將其作爲輸出回顯。一旦轉換爲輸出,理論上應該可以在某處傳送。整潔的想法。我們在這裏忽略同時性問題,那麼可以做到嗎?由於某種原因,下面的構思並不完全適用。 – markie

0

這不能準確地完成如圖所示,但執行您的例子中,你可以使用cat的加入文件一起的能力:

cat <(echo ls) - | /bin/sh 

(你可以做-i,但你得有另一個進程終止/ bin/sh的,因爲你的嘗試Ctrl-C和Ctrl-D將失敗。)

這假定你想傳遞你的管道輸入,然後從標準輸入接受。你也可以使它在stdin完成後或雙方都做一些事情 - 但它不會逐字符或逐行地合併輸入。

+0

這是一個整潔的想法,但行爲很奇怪。當我按'up'時,我看不到shell提示符或以前的命令。但我可以鍵入和運行命令。要退出,我需要輸入'exit'並按兩次輸入。什麼導致這些奇怪的事情? – markie

+0

噢,用-i我可以看到shell提示符,但它並沒有真正響應我輸入的內容(Ctrl C使它再次打印shell提示,輸入或忽略任何命令)。什麼!? – markie

+0

@markie:沒有-i,shell不是交互式的,所以它運行在一個更適合腳本的模式下。腳本不需要提示,並且不需要通過「向上」的先前命令。實際上,我並不確定退出的方面,因爲我沒有注意到這一點。 使用-i它試圖連接到終端,但問題是管道不像終端一樣 - 例如,Ctrl-C不生成信號,而是作爲另一個字符進行處理。 –

0

如果我正確理解你的要求,你想這個設置(ASCII藝術中脫穎而出):

o----+----->| A |----+---->| B |---->o 
    |    ^
    |     | 
    +------------------+ 

與另外的約束,如果進程A關閉了店鋪,進程B應該能夠繼續輸入流將轉到B.

這是一個非標準設置,如您所知,並且只能通過使用輔助程序將輸入驅動到A和B才能實現。最終會產生一些有趣的同步問題,但只要您的信息足夠短,這一切就會發揮出色。

實現此目標所需的管道是值得注意的 - 您需要兩根管道,一根用於輸入到A,另一根用於輸入到B,而A的輸出也將連接到B的輸入。

o---->| C |---------->| A |----+---->| B |---->o 
     |      ^
     |       | 
     +--------------------------+ 

注意是c將被兩次寫入數據,一旦A和一次B.注意,那就是,從A到B的管是相同的管材作爲從C到A.

0

這似乎做你想要什麼:

 
$ (./a <&-; cat) | ./b 

(它,如果你想獲得輸入並不清楚我...這個解決方案將所有輸入到b) 當然,在這種情況下,輸入b嚴格排序: 的所有輸出先發送給b,然後a終止,th en輸入到b。如果你想要的東西 交錯,嘗試:

 
$ (./a <&- & cat) | ./b 
+0

這是一個簡潔的想法,但我試着用問題中提供的測試案例解決您的問題,並且無法使其工作。 「(echo ls; cat)|/bin/sh -i」似乎確實給了我一個shell,我可以鍵入,但它不接受任何我輸入的內容。這裏發生了什麼? – markie

1

從控制終端設備/dev/tty讓你有給定的測試用例工作while ... read一個sh -c '...'構造內。

請注意使用eval(這裏可以避免嗎?),並且input>上的多行命令將失敗。

echo 'ls; export var=myval' | ( 
stdin="$(</dev/stdin)" 
/bin/sh -i -c ' 
    eval "$1"; 
    while IFS="" read -e -r -p "input> " line; do 
    history -s "${line}" 
    eval "${line}"; 
    done </dev/tty 
' argv0 "${stdin}" 
) 

input> echo $var 

對於類似的問題,在使用命名管道在這裏看到:

BASH: Best architecture for reading from two input streams