在 bash 管道行之间执行命令......?

在 bash 管道行之间执行命令......?

我想运行一系列管道命令,执行大量音频处理。伪代码如下:

command1 | command2 | command3

对于 command2 和 command3,都将前一个命令的输出作为输入(常规 stdin/stdout 行为)。

现在我想在 command1 之后立即执行另一个 command1.1,它与 command1 和 command2 之间的运行管道没有任何关联,只是它不能在 command1 完全完成之前运行。

command1 [; after that run command1.1, even if command2 and command3 are still busy] command2 command3

但是我不知道如何在 bash 中执行此操作。我尝试过 tee,但这会使命令在管道构建后立即运行。有什么想法吗?

谢谢!

答案1

您可以将其重定向到子 shell。

command1 & > >(command2 | command3) &
wait $!      # Wait end of process $! (actually the pid of command1)
command_1.1     

另一种方法是创建命名管道先进先出.
脚本应该类似于

MYFIFO=/tmp/myfifo.$$
rm -f $MYFIFO
mkfifo $MYFIFO
command1 > $MYFIFO &
MYPROGRAM_PID=$!
cat $MYFIFO  | command2 | command3 &
wait $MYPROGRAM_PID   # Wait end of process $MYPROGRAM_PID
command_1.1     

答案2

最重要的部分是“之后”——UNIX 管道对“之后”的唯一概念是,它们通常会关闭,但它们会在第一个命令完成后执行开始,而不是在 ist 之后结束

所以你需要做的是使用一个 shell 脚本 - 它确实有“一个接一个”的概念:

echo 'command1' > myscript.sh
echo 'command1.1 >&2' >> myscript.sh
chmod 755 myscript.sh

(当然你可以使用你最喜欢的编辑器来实现这一点),然后运行

myscript.sh | command2 | command3

现在发生的情况是,的输出command1将是 shell 脚本的输出,因此您的管道可以正常工作。在您的脚本内部,的输出command1.1将被重定向到脚本的 STDERR,因此它不会发送到管道,而是发送到终端

答案3

最简单的构造是:

(command1 ; command1.1) | command2 | command3

这样做有两个潜在问题。如果command1.1在 stdout 上产生任何输出,它将通过管道发送。此外,在完成command2之前不会在 stdin 上看到 EOF 。command1.1

如果管道最初在 stdout 和 stderr 文件描述符都指向同一文件结构的上下文中调用,那么有一个简单的方法可以解决这两个问题:

(command1 ; exec 1>&2 command1.1) | command2 | command3

这将导致 command1.1 的 stdout 指向 stderr,而该 stderr 未被管道重定向。

如果最初 stdout 和 stderr 可能是两个不同的文件描述符,则可以使用上述方法,将初始 stdout 暂时存放在另一个文件描述符编号中。因此,除非您绝对需要将 stdout 和 stderr 分开command1.1,否则我不会采用这种方法。

为了完整性,如果你想这样做,它可能看起来像这样:

(((exec 9>&- command1) ; exec 1>&9 9>&- command1.1) | exec 9>&- command2 | exec 9>&- command3) 9>&1

相关内容