cmd_drain <

cmd_drain <

众所周知,该cmd | read -r var1 var2构造在 bash 中不起作用,因为由于管道的原因,读取命令是在子 shell 中执行的。我曾经用来read -r var1 var2 <<< "$(cmd)"解决这个问题,但最近我了解了这个cmd_drain < <(cmd_src)结构,它似乎也同样有效:read -r var1 var2 < <$(cmd)

这两种解决方案有区别吗?没有似乎在微不足道的情况下有任何区别:

$ hd < <(echo Hello)
00000000  48 65 6c 6c 6f 0a                                 |Hello.|
00000006
$ hd <<< $(echo Hello)
00000000  48 65 6c 6c 6f 0a                                 |Hello.|
00000006

我还尝试了一些特殊字符并得到了相同的结果。我的直觉是,结果将始终是相同的,期望cmd_drain <<< "$(cmd_src)"首先运行cmd_src并将整个结果缓冲在内存中,然后再将其输入到cmd_drain,同时cmd_drain < <(cmd_src)将不断地将输出输入cmd_srccmd_drain。我认为它的行为就像cmd_src | cmd_drain除了cmd_src将在子 shell 中运行而不是在cmd_drain.我的假设正确吗?

额外问题:围绕结构是否需要引用$()

答案1

是的,你的假设是正确的。在cmd_drain < <(cmd_src)(又名流程替代,与正常重定向相结合),Bash 将替换<(cmd_src)为文件的路径,从中cmd_src可以读取 的输出。来自文档:

进程列表异步运行,其输入或输出显示为文件名。该文件名作为扩展结果作为参数传递给当前命令。如果>(list)使用表单,写入文件将为列表提供输入。如果 <(list)使用该形式,则应读取作为参数传递的文件以获得 list 的输出。

在 中cmd_drain <<< "$(cmd_src)"<<< ...被像其他任何一样对待这里的字符串, 所以:

该单词会经历波形符扩展、参数和变量扩展、命令替换、算术扩展和引号删除。不执行路径名扩展和分词。结果作为单个字符串提供给标准输入上的命令,并附加换行符 [...]

因此,您不需要$()在那里引用,但特别是因为此处的字符串<<<语法不会进行分词或文件名扩展。通常,你必须这么做。


再次注意此处字符串文档的最后一句 - 附加了换行符:

bash-5.0$ od -c <<< $(printf %s foo)
0000000   f   o   o  \n
0000004
bash-5.0$ od -c < <(printf %s foo)
0000000   f   o   o
0000003

这是否重要取决于您正在运行的内容。

在 中hd <<< $(echo Hello),命令替换删除了 的尾随换行符输出echo,并且此处字符串添加了一个换行符,从而有效地为您提供了相同的输出。但是,如上面的示例所示,删除/添加换行符可能很棘手,并且您不需要确切地获得什么cmd_src输出。

相关内容