【问题标题】:why process substitution does not always work with while loop in bash?为什么进程替换并不总是适用于 bash 中的 while 循环?
【发布时间】:2015-05-09 17:35:34
【问题描述】:

process substitution 可以很好地处理文件名,例如两者都有

$ cat <FILENAME

$ while read i; do echo $i; done <FILENAME

工作。

但如果我们使用echo 命令(或任何其他生成输出到标准输出的命令)而不是 FILENAME,cat 将继续工作

$ cat <(echo XXX)
XXX

while 循环

$ while read i; do echo $i; done <(echo XXX) 
bash: syntax error near unexpected token `<(echo XXX)'

产生错误。

有什么想法吗?

【问题讨论】:

    标签: bash process while-loop substitution


    【解决方案1】:

    注意:<b>&lt;</b><em>filename</em>不是进程替换。这是redirection。进程替换的格式为<b>&lt;(</b><em>command</em><b>)</b>

    进程替换用进程的名称替换&lt;(...)。尽管使用了 符号,但它不是重定向。

    所以当你说cat &lt;(echo foo) 时,bash 会创建一个子进程来运行echo 命令,并替换一个可以读取的伪文件的名称以获取该命令的输出。替换的结果将是这样的:

    cat /dev/fd/63
    

    请注意没有重定向。 (您可以通过输入 echo &lt;(echo foo) 来查看此操作。)

    像许多实用程序一样,cat 可以在有或没有命令行参数的情况下调用;如果未指定文件,则从stdin 读取。所以cat file.txtcat &lt; file.txt 非常相似。

    但是while 命令不接受额外的参数。所以

    while read -r line; do echo "$line"; done < file.txt 
    

    有效,但是

    while read -r line; do echo "$line"; done file.txt
    

    是语法错误。

    流程替换不会改变这一点。所以

    while read -r line; do echo "$line"; done /dev/fd/63
    

    是语法错误,因此也是

    while read -r line; do echo "$line"; done <(echo foo)
    

    要从进程替换中指定重定向,您需要一个重定向:

    while read -r line; do echo "$line"; done < <(echo foo)
    

    请注意,两个 符号之间必须有一个空格,以避免与“here-doc”语法&lt;&lt;word 混淆。

    【讨论】:

    • 很好的答案。非常彻底
    • 大师收我为徒 :)
    • 多么过山车啊! “上半场有我们,不会撒谎”——直到最后一行,我都以为我在读坏消息。谢谢!
    • 令人印象深刻的答案!
    【解决方案2】:

    我为愚蠢道歉,刚刚找到了可行的解决方案

    $ while read i; do echo $i; done < <(echo XXX)
    XXX

    如果有人能用双减号 &lt; &lt; 解释这种奇怪语法背后的想法,我将非常感激。

    【讨论】:

    • 这不是愚蠢的。你准确地假设了一个人应该能够假设的东西。你的假设是错误的,这更多地反对bash语言的设计者,而不是反对你。
    【解决方案3】:

    进程替换操作会生成一个文件名,通常在/dev/fd 中,尽管这不是强制性的。需要从这些方面考虑;它可以用于可以使用文件名的地方。

    您可以查看它的作用,例如:

    echo <(cat /etc/passwd)
    

    你的例子表明了这一点。 cat 命令接受文件名参数。 done 关键字不接受文件名参数,但接受 I/O 重定向。

    您可以确定该符号令人困惑;在某些方面,确实如此。但是抱怨没有什么意义。这就是 Bash 的做法。您可以使用不同的符号创建自己的 shell,但出于向后兼容性的原因,Bash 将继续支持当前的符号。

    【讨论】:

      猜你喜欢
      • 2015-12-12
      • 1970-01-01
      • 2014-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      • 2013-05-07
      相关资源
      最近更新 更多