我想运行一系列管道命令,执行大量音频处理。伪代码如下:
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