将 stdin 传递给进程 A 和进程 B(由 A 调用)

将 stdin 传递给进程 A 和进程 B(由 A 调用)

假设交互式进程 A 从终端读取输入,并且偶尔生成进程 B,进程 B 也从终端读取输入。举个例子,A 读取一个数字并将控制权传递给 B,B 读取任何内容。

编辑:A 和 B 不是同时运行,在特定场景中 A 使用 调用system()B。

是否可以重定向标准输入,以便 AB 从标准输入读取?

实验表明,天真的

echo -e '123\nxyzzy' | A

其中 123 应该由 A 读取,而 xyzzy 由 B 读取则不起作用。

答案1

可以将输入提供给多个进程。当多个进程从同一管道或终端读取数据时,每个字节都会进入其中一个进程,以最先读取该特定字节的进程为准。当只有一个进程正在主动读取时,它会获取输入。当多个进程同时主动读取时,哪一个进程获得输入是不可预测的。

你遇到了冲突缓冲。大多数程序(显然包括 A)一次读取整个缓冲区的输入(通常是几百字节或几千字节),然后将其存储在自己的内存中,直到它们开始处理它。这比一次读取一个字节要快得多。但在这种情况下,这意味着 A 在调用 B 之前读取的内容多于它将处理的部分,因此当 B 启动时,B 的输入已经被 A 消耗了。

如果你可以让 B 从不同的来源读取,这当然是一个解决方案。

如果您可以控制 A 的执行方式,请尝试stdbuf来自 GNU coreutils。它挂钩到库调用,使进程一次读取一个字节。这适用于大多数程序,但不是全部:它不适用于静态链接的可执行文件,并且如果程序使用标准库 (stdio) 以外的缓冲方法,它也不起作用。

… | stdbuf -i 1 A

或者,尝试从常规文件中读取。当 A 从管道或终端读取输入时,它无法将其放回。但是,当从常规文件中读取它时,它可以在调用 B 之前倒回读取位置。read例如,这就是 shell 内置函数的行为方式。不能保证特定的程序 A 会执行此操作,事实上这不是很常见的行为,但如果确实如此,那就是一个简单的解决方案。

如果这不起作用,或者如果您无法控制 A 的执行方式,则需要安排输入的时间,以便在 B 启动之前不会出现用于 B 的部分。如何做到这一点取决于您如何检测 B 已启动。一种可能的解决方案,但很脆弱,就是推迟:

{ echo 123; sleep 1; echo xyzzy; } | A

这只适用于 A 在 1 秒内调用 B 的情况,这是脆弱的。更可靠的解决方案是检测 A(或 B)产生的输出。这是这样的问题预计旨在解决。例如,如果 B 显示某种提示,例如B>

#!/usr/bin/expect -f
spawn A
send "123\r"
expect "B>"
send "xyzzy\r"

答案2

这是一个缓冲问题。进程 A 使用 stdio 从 stdin 读取相当多的数据块,因此当 B 收到控制权时,用于 B 的部分已经消失了。一个可能的解决方案是像这样填充输入:

python -c 'print("123" + "\n"*4093 + "xyzzy\n")' | A

按预期工作(实际缓冲区大小 - 此处为 4096 - 可能需要调整)。

相关内容