2011-06-23 106 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