众所周知,cmd | read -r var1 var2构造在bash中不工作,因为由于管道的原因,读取命令在子subshell中执行。我过去经常使用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_src的输出输入cmd_drain。我假设它的行为类似于cmd_src | cmd_drain,只是cmd_src将在子shell中运行,而不是在cmd_drain中运行。我的假设正确吗?
附加问题:围绕$()结构引用是否必要?
发布于 2019-01-15 10:21:36
是的,你的假设是正确的。在cmd_drain < <(cmd_src) (又称过程替代,结合普通重定向)中,Bash将用文件路径代替<(cmd_src),从该路径可以读取cmd_src的输出。从医生那里:
进程列表异步运行,其输入或输出显示为文件名。作为展开的结果,此文件名作为参数传递给当前命令。如果使用
>(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输出。
https://unix.stackexchange.com/questions/494574
复制相似问题