在 shell 脚本中,我想使用命名管道写入外部进程 X 的 stdin,并且想将 stdout/stderr 从另一个命名管道发送到当前终端。
外部进程 X 通过 PIPEIN 接收 stdin,并将其 stdout/stderr 发送到 PIPEOUT。
tail -f $(tail -F PIPEOUT) & # (1) this is completely wrong, need help here
for i; do
echo "${i}" > PIPEIN # send stdin to X
done
echo "[stdin end]" > PIPEIN # signal that we are done writing (there might be a better way lol)
所以在上面的脚本中,我们已经启动了进程X,它已经运行了一段时间。但是现在,当我们运行上面的脚本时,我们想要向 X 发送一些标准输入,并且我们想要使用 PIPEOUT 从进程 X 中读取标准输出。
我上面想做的是在将 stdin 发送到 X 之前设置对 PIPEOUT 的读取,以确保捕获 X 的所有 stdout/stderr 。问题是我不知道如何运行某些后台进程(tail 或 cat 从 PIPEOUT 读取)并将该 stdio 发送到当前终端。
有谁知道我在说什么。如果我没有记错的话,我只需要修复标记为 (1) 的行,并以某种方式在后台设置一个读取,可以从 PIPEOUT 读取并将该 stdio 以某种方式发送到当前终端/tty。
答案1
我不清楚你想做什么tail -f $(tail -F PIPEOUT) &
。这是tail -f
ing 文件是的结果 tail -F
,通常永远不会终止。我的假设是您希望输出通过管道的所有内容,无论需要多长时间。
just 的问题tail -f
是它必须在输出任何内容之前找到文件的末尾,而对于管道来说这永远不会发生。你可以给出tail
一个明确的起点,而不是-n +x
,选择起始行(从头开始,从 1 开始索引)。tail -n 1 -f foo
将显示它可以从中获取的所有内容foo
。
tr 'a-z' 'A-Z' < PIPEIN > PIPEOUT & # for example
tail -n +1 -f PIPEOUT &
for i in a b c d ; do
echo $i > PIPEIN
done
echo "[stdin end]" > PIPEIN
但请注意,这echo > foo
将在写入该行后关闭 foo — 另一端的命令需要乐意处理该问题。如果这个例子是人为的并且真实的输入来自其他地方,你可以忽略它。
另请注意该tail
过程永远不会终止——它一直期待着更多的东西可能会通过管道。您必须自己显式地杀死它,也许可以使用 shell 的作业控制。如果输出中有某种模式表明它已完成,您可能会发现retail
(“带有正则表达式的尾部”)有用 -retail -n +1 -f -u REGEX PIPEOUT
当出现匹配的行时将终止REGEX
。(作为免责声明,我retail
几年前为此目的撰写了这篇文章)
答案2
仅打开 PIPEIN 进行写入一次,程序就会终止 - 即使有 2 秒的延迟:
mkfifo PIPEIN PIPEOUT
tr 'a-z' 'A-Z' < PIPEIN > PIPEOUT & # for example
tail -n +1 -f PIPEOUT &
(
for i in a b c d ; do
echo $i
done
sleep 2
echo "[stdin end]"
) > PIPEIN
如果您多次打开 fifo,则 fifo 的读取器可能会认为它已关闭,因此写入器将被挂起,直到另一个读取器从 fifo 读取数据。
所以保存的赌注是只打开 PIPEIN 一次。否则您可能会看到程序锁定。