【问题标题】:Pipe stdout to multiple processes [zsh]管道标准输出到多个进程 [zsh]
【发布时间】:2011-02-14 17:45:09
【问题描述】:

我知道 zsh 的能力:

ls -1 >foo >bar

但是假设我想通过另一个命令运行这两个输出。例如,我将如何组合这两个命令以避免运行 mysqldump 两次?

mysqldump db1 | bzip2 > db1.sql.bz2
mysqldump db1 | mysql db2

我能想到的最接近的是:

mysqldump db1 >db1.sql | mysql db2
bzip2 db1.sql

但我宁愿不将文件未压缩地写入磁盘(它很大!)。

【问题讨论】:

    标签: pipe zsh


    【解决方案1】:

    以下作品:

    echo abc > >(gzip > 1) > >(xz > 2)
    

    针对您的示例进行了修改(但未经测试):

    mysqldump db1 > >(bzip2 > db1.sql.bz2) > >(mysql db2)
    

    或者,可能更好:

    { mysqldump db1 } > >(bzip2 > db1.sql.bz2) > >(mysql db2)
    

    //我在man zshexpn的PROCESS SUBSTITUTION部分找到了几乎相同的例子:

    还请注意,前面的示例可以更简洁有效地编写(前提是设置了 MULTIOS 选项):

       paste <(cut -f1 file1) <(cut -f3 file2) \
       > >(process1) > >(process2)
    

    在上面的例子中,shell 使用管道而不是 FIFO 来实现后两个进程替换。

    >(进程)还有一个问题;当它附加到外部命令时,父 shell 不会等待进程完成,因此紧随其后的命令不能依赖于完成的结果。问题和解决方法与 zshmisc(1) 中的 MULTIOS 一节中描述的相同。因此,在上面示例的简化版本中:

       paste <(cut -f1 file1) <(cut -f3 file2) > >(process)
    

    (注意不涉及 MULTIOS),进程将异步运行。解决方法是:

       { paste <(cut -f1 file1) <(cut -f3 file2) } > >(process)
    

    这里的额外进程是从等待它们完成的父 shell 产生的。

    【讨论】:

      【解决方案2】:

      您可以使用进程替换。

      在 zsh 中:

      ls -1 > >(grep foo) > >(grep bar)
      

      在 bash 中:

      ls -1 | tee >(grep foo) >(grep bar) >/dev/null
      

      进程替换为您管理命名管道。

      【讨论】:

      • +1 - 我接受了@ZyX,因为它是一个更完整的答案 - 它解决了等待命令完成的问题 - 但我喜欢这里使用 bash 和 tee 的选项,因为我并不总是在 zsh 中。谢谢!
      【解决方案3】:

      您可以通过fifo 连接进程并使用tee 实用程序将标准输出复制到每个fifo 和stdout。比如:

      mkfifo db1.sql
      bzip2 db1.sql &
      mysqldump db1 | tee db1.sql | mysql db2
      

      【讨论】: