3

我想运行一个程序“A”,让它的输出进入另一个程序“B”的输入,以及标准输入进入“B”的输入。如果程序“A”关闭,我希望“B”继续运行。

我可以轻松地将 A 输出重定向到 B 输入:
./a | ./b

如果我愿意,我可以将 stderr 合并到输出中:
./a 2>&1 | ./b

但我不知道如何将标准输入结合到输出中。我的猜测是:
./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 重定向到管道时都做任何复杂的事情)。

4

6 回答 6

3

不编写辅助程序就无法做到这一点。

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

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

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

因为你想要的基本上是“tee”的反义词,我可以称之为“eet”......

[编辑]

要是你能在后台启动“猫”就好了……

但这将失败,因为具有控制终端的后台进程无法从标准输入读取。因此,如果您可以将“猫”从其控制终端中分离出来并在后台运行它...

在 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 重定向标准输入所必需的。

在这里,echo HELLO代表您的“程序 A”。这些seq命令(sleep中间有 )只是为了提供一些输入。是的,您可以将整个事情通过管道传递给进程 B。

关于你可以要求的丑陋和不可移植的解决方案......

于 2011-06-23T14:45:19.240 回答
1

管道有两端。一个是写的,写出来的出现在另一端,也就是读。

它是一个管道,而不是 T 形或 Y 形接头。

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

于 2011-06-23T14:39:30.100 回答
1

要使给定的测试用例工作,您必须从构造内while ... read的控制终端设备开始。/dev/ttysh -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:从两个输入流中读取的最佳架构

于 2011-09-08T13:41:33.723 回答
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 的管道是同一管道。

于 2011-06-23T16:13:43.147 回答
0

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

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

(您可以执行 -i,但是您必须让另一个进程终止 /bin/sh,因为您尝试 Ctrl-C 和 Ctrl-D 退出将失败。)

这假设您要传入管道输入,然后从标准输入接受。你也可以让它在标准输入完成后做一些事情,或者在两边做一些事情——但它不会逐个字符或逐行合并输入。

于 2011-06-23T14:59:03.837 回答
0

这似乎做你想做的事:

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

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

$ ( ./a <&- & cat ) | ./b
于 2011-06-23T16:56:20.070 回答