为什么进程替换并不总是适用于 bash 中的 while 循环?
why process substitution does not always work with while loop in bash?
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)'
产生错误。
知道为什么吗?
我为我的愚蠢道歉,刚刚找到了可行的解决方案
$ while read i; do echo $i; done < <(echo XXX)
XXX
如果有人能用双少符号解释这种奇怪语法背后的想法,我将非常感激,< <
。
注:<b><</b><em>文件名</em>
是不进程替换。这是一个redirection。进程替换的格式为 <b><(</b><em>command</em><b>)</b>
。
进程替换用 进程名称 替换 <(...)
。尽管使用了 < 符号,但它不是重定向。
所以当你说 cat <(echo foo)
时,bash 创建一个子进程到 运行 echo
命令,并替换一个可以读取的伪文件的名称获取该命令的输出。替换的结果将是这样的:
cat /dev/fd/63
注意没有重定向。 (您可以通过键入 echo <(echo foo)
来查看实际效果。)
像许多实用程序一样,cat
可以使用或不使用命令行参数来调用;如果未指定文件,则从 stdin
读取。所以 cat file.txt
和 cat < 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)
请注意,两个 < 符号之间必须有一个 space,以避免与 "here-doc" 语法 <<word
混淆。
进程替换操作生成一个文件名,通常在 /dev/fd
中,尽管这不是强制性的。需要用这些术语来考虑;它可以用在可以使用文件名的地方。
你可以看看它的作用,例如:
echo <(cat /etc/passwd)
你的例子说明了这一点。 cat
命令接受文件名参数。 done
关键字不接受文件名参数,但接受 I/O 重定向。
您可以确定该符号令人困惑;在某些方面,它是。但抱怨毫无意义。 Bash 就是这样做的。您可以使用不同的表示法自由创建自己的 shell,但出于向后兼容性的原因,Bash 将继续支持当前的表示法。
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)'
产生错误。
知道为什么吗?
我为我的愚蠢道歉,刚刚找到了可行的解决方案
$ while read i; do echo $i; done < <(echo XXX)
XXX
如果有人能用双少符号解释这种奇怪语法背后的想法,我将非常感激,< <
。
注:<b><</b><em>文件名</em>
是不进程替换。这是一个redirection。进程替换的格式为 <b><(</b><em>command</em><b>)</b>
。
进程替换用 进程名称 替换 <(...)
。尽管使用了 < 符号,但它不是重定向。
所以当你说 cat <(echo foo)
时,bash 创建一个子进程到 运行 echo
命令,并替换一个可以读取的伪文件的名称获取该命令的输出。替换的结果将是这样的:
cat /dev/fd/63
注意没有重定向。 (您可以通过键入 echo <(echo foo)
来查看实际效果。)
像许多实用程序一样,cat
可以使用或不使用命令行参数来调用;如果未指定文件,则从 stdin
读取。所以 cat file.txt
和 cat < 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)
请注意,两个 < 符号之间必须有一个 space,以避免与 "here-doc" 语法 <<word
混淆。
进程替换操作生成一个文件名,通常在 /dev/fd
中,尽管这不是强制性的。需要用这些术语来考虑;它可以用在可以使用文件名的地方。
你可以看看它的作用,例如:
echo <(cat /etc/passwd)
你的例子说明了这一点。 cat
命令接受文件名参数。 done
关键字不接受文件名参数,但接受 I/O 重定向。
您可以确定该符号令人困惑;在某些方面,它是。但抱怨毫无意义。 Bash 就是这样做的。您可以使用不同的表示法自由创建自己的 shell,但出于向后兼容性的原因,Bash 将继续支持当前的表示法。