【问题标题】:What is happening behind bash forward process substitution?bash 正向进程替换背后发生了什么?
【发布时间】:2013-04-17 21:44:45
【问题描述】:

根据维基百科,“进程替换也可用于捕获通常会进入文件的输出,并将其重定向到进程的输入。”(http://en.wikipedia.org/wiki/Process_substitution)。

所以,用我自己的话来说,这意味着通过进程替换,我可以获取命令 A 的输出并将其用作命令 B 的输入。换句话说,它就像一个管道(这是正确的吗?) .

如果这是真的,如果我这样做:

echo "test" >(wc)

那么我应该期望得到以下结果:

1 1 5

因为我对上面命令的理解和下面类似:

$echo "test" > tmp
$wc tmp
1 1 5 tmp

除了我不使用进程替换制作 tmp 文件。

但我得到以下输出:

test /dev/fd/63

这显然表明我的心智模型不正确。我哪里错了?

我理解

$diff <(head file1) <(head file2) 

完全有道理。但不是>(命令)。

【问题讨论】:

    标签: bash process


    【解决方案1】:

    来自Process Substitution

    进程列表在其输入或输出连接到 FIFO 或/dev/fd 中的某个文件的情况下运行。 此文件的名称作为参数传递给当前命令作为扩展的结果。如果使用 >(list) 形式,写入文件将为列表提供输入

    echo "test" &gt;(wc) 会发生什么?

    打开文件/dev/fd/63 用于连接echo testwcwc 以连接到 /dev/fd/63 的输入开始。然后将该文件的名称 (/dev/fd/63) 作为参数传递给当前命令 (echo "test"),从而得到 echo "test" /dev/fd/63。这就是你看到的原因

    test /dev/fd/63
    

    作为输出。 wc 等待输入,但由于 echo 不写入 /dev/fd/63,计数将是 0

    如果你想让它工作,你必须创建一个脚本,它接受最后一个参数并将第一个 N-1 参数回显到最后一个

    #! /bin/bash
    echo "${@:1:$(($# - 1))}" >${@: -1}
    

    当你调用它时

    bash script.sh test >(wc)
    

    你会看到预期的输出

    1 1 5
    

    【讨论】:

    • 或者,更简单的是,使用:echo test &gt; &gt;(wc),它将“echo”的输出重定向到进程替换指定的文件。
    • @JonathanLeffler 哇!我真的很感动。因此,名称不会作为参数传递,而是按字面意思附加到命令字符串中。谢谢。
    • 参见bash 手册中关于Shell Expansions 的讨论以及描述特定扩展的以下部分,然后是在所有扩展之后发生的Redirections
    【解决方案2】:

    您的心智模型不正确,因为您遗漏了一个重要细节:流程替换不是重定向。

    当您执行“echo test > tmp”之类的重定向时,执行的是“echo test”,标准输出(由“>”表示)被定向到名为“tmp”的文件中。当您执行替换时,例如“echo test >(wc)”,“wc”被执行,“>(wc)”被替换为文件名(或者可能是魔法设备的名称)可以读取或写入。

    正如您链接到的维基百科页面所引用的那样:“在后台,进程替换通过创建命名管道,然后在命令行上替换其名称来工作。”

    如果您仔细查看上面的“差异”示例,您也会发现它的工作方式相同。毕竟,除了命令行上的文件名之外,“diff”的参数是什么?

    【讨论】:

    • 这是否意味着执行的优先级是 1) wc inside >() 和 2) echo 命令?
    • 如果我理解正确,使用另一个示例$ tee &gt;(wc -l &gt;&amp;2) &lt; bigfile | gzip &gt; bigfile.gz,这里 bigfile 被读取并成为 >() 内 wc -l 的输入,并且该输出被作为输入发球台?
    • 示例$ tee &gt;(wc -l &gt;&amp;2) &lt; bigfile | gzip &gt; bigfile.gz 等价于$ cat bigfile | tee &gt;(wc -l &gt;&amp;2) | gzip &gt; bigfile.gz。 tee 命令在 stdin 上获取 bigfile,stdout 是 gzip 的管道,而 tee 的 命令行参数 是代表 wc 进程的 stdin 的文件名。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-04
    • 1970-01-01
    • 2016-06-28
    • 2018-03-21
    • 1970-01-01
    • 2019-08-23
    • 1970-01-01
    相关资源
    最近更新 更多