why process substitution does not always work with while loop in bash?

放肆的年华 提交于 2019-12-05 17:44:37

问题


The process substitution works with filenames fine, e.g. both

$ cat <FILENAME

and

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

work.

But if instead of FILENAME we use echo command (or any other, which generates output to stdout), cat continues to work

$ cat <(echo XXX)
XXX

while the loop

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

produces error.

Any ideas why?


回答1:


Note: <filename is not process substitution. It's a redirection. Process substitution has the format <(command).

Process substitution substitutes the name of a process for the <(...). Despite the use of the < symbol, it is not a redirect.

So when you say cat <(echo foo), bash creates a subprocess to run the echo command, and substitutes the name of a pseudo-file which can be read to get the output of that command. The result of the substitution will be something like this:

cat /dev/fd/63

Note the absence of a redirect. (You can see this in action by typing echo <(echo foo).)

Like many utilities, cat can be invoked with or without a command-line argument; if no file is specified, then it reads from stdin. So cat file.txt and cat < file.txt are very similar.

But the while command does not accept additional arguments. So

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

is valid, but

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

is a syntax error.

Process substitution doesn't change that. So

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

is a syntax error, and consequently so is

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

To specify the redirect from the process substitution, you need a redirect:

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

Note that there must be a space between the two < symbols to avoid confusion with the "here-doc" syntax, <<word.




回答2:


I apologize for stupidity, just have found the working solution

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

I will be really thankfull if somebody can explain the idea behind this strange syntax with double less sign, < <.




回答3:


The process substitution operation generates a file name, usually in /dev/fd though that isn't mandated. It needs to be thought of in those terms; it can be used where a file name can be used.

You can see what it does with, for example:

echo <(cat /etc/passwd)

Your examples show this. The cat command accepts file name arguments. The done keyword does not accept file name arguments, but does accept I/O redirection.

You can decide that the notation is confusing; in some respects, it is. But there is little point in complaining. That is the way Bash does it. You are at liberty to create your own shell using a different notation, but Bash will continue to support the current notation for reasons of backwards compatibility.



来源:https://stackoverflow.com/questions/28927162/why-process-substitution-does-not-always-work-with-while-loop-in-bash

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!