将stdin _and_ stdout重定向到管道

时间:2011-06-23 14:36:06

标签: linux shell redirect io-redirection

我想运行程序“A”,将其输出转到另一个程序“B”的输入,以及stdin转到“B”的输入。如果程序“A”关闭,我希望“B”继续运行。

我可以轻松地将A输出重定向到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的重定向时做任何复杂的事情到管道)。

6 个答案:

答案 0 :(得分:3)

如果不编写辅助程序,就无法完成。

通常,stdin可能是只读文件描述符(哎呀,它可能指的是只读文件)。所以你不能“插入”任何东西。

您需要编写一个“帮助程序”程序来监视两个文件描述符(例如,0和3),以便从两者中读取并“合并”它们。一个简单的selectpoll循环就足够了,您可以用大多数脚本语言编写它,但不是shell,我不这么认为。

然后你可以使用shell重定向将程序的输出提供给“helper”的描述符3。

既然你想要的基本上与“tee”相反,我可以称之为“eet”......

[编辑]

如果只有你可以在后台启动“猫”......

但是这会失败,因为具有控制终端的后台进程无法从stdin读取。所以,如果你可以从控制终端分离“cat”并在后台运行它......

在Linux上,“setsid cat”应该粗略地做到这一点。但是(a)我不能让它工作得很好而且(b)我今天真的没有时间和(c)它是非标准的。

我会编写帮助程序。

[编辑2]

好的,这似乎有效:

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

set -m事件强制bash启用作业控制,显然需要防止shell从/ dev / null重定向stdin。

此处,echo HELLO代表您的“程序A”。 seq命令(中间有sleep)只是为了提供一些输入。是的,你可以将整个事情告诉处理B.

关于丑陋和不便携的解决方案,你可以要求......

答案 1 :(得分:1)

管道有两端。一个用于写作,写入的另一个用于阅读。

这是一个管道,而不是T或Y交界处。

我认为你的情景不可能。 “stdin要输入”任何东西都没有意义。

答案 2 :(得分:1)

要使给定的测试用例正常工作,您必须从while ... read构造内的控制终端设备/dev/tty 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

答案 3 :(得分:0)

这不能完全按照图示完成,但为了执行您的示例,您可以利用cat将文件连接在一起的能力:

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

(你可以做-i,但是你必须让另一个进程终止/ bin / sh,因为你尝试Ctrl-C和Ctrl-D out会失败。)

这假定您要传入管道输入,然后从stdin接受。您也可以使它在stdin完成后或双方都做某事 - 但它不会逐个字符或逐行合并输入。

答案 4 :(得分: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的管道是相同的管道。

答案 5 :(得分:0)

这似乎可以做你想要的:

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

(我不清楚你是否想获得输入......这个解决方案将所有输入发送到b) 当然,在这种情况下,b的输入是严格排序的:a的所有输出 首先发送到b,然后终止,然后输入到b。如果你想要的东西 交错,尝试:

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