为什么这个循环是针对空集执行的?

Sae*_*ati 0 bash find here-document

创建一个空目录,然后运行以下代码:

find /empty_directory -mindepth 1 -maxdepth 1 -type d |
while read dir;
do
    echo "Simple find: $dir"
done

printf '%s\n' '-----'                   # Safer than    echo -----

while read dir;
do
    echo "HereDoc find: $dir"
done <<< "$(find /empty_directory -mindepth 1 -maxdepth 1 -type d)"
Run Code Online (Sandbox Code Playgroud)

这是输出:

-----
HereDoc find: 
Run Code Online (Sandbox Code Playgroud)

换句话说,第二个循环使用空变量执行一次。

为什么会这样呢?当没有发现循环的目录时,如何使第二个循环行为正确并且不运行?

G-M*_*ca' 5

\xe2\x80\x99s 发生了什么?

\n

我知道您\xe2\x80\x99正在尝试解决\xc2\xa0特定问题,\n但调试的首要规则之一是\xc2\xa0简化场景。\xc2\xa0\n如果\xc2\xa0we\xc2 \xa0do

\n
$ sleep 1 | read x\n$ echo "$?"\n1\n\n$ read x <<< $(sleep 1)\n$ echo "$?"\n0\n
Run Code Online (Sandbox Code Playgroud)\n

我们看到read来自空管道的 a 失败,\n但是read来自 a\xc2\xa0null 的 a\xc2\xa0 这里字符串成功(读取 a\xc2\xa0null 值)。\xc2\xa0\n这就是您所看到的。

\n

它\xe2\x80\x99s 在bash(1)中拼写出来:

\n
\n

这里是字符串

    \n这里文档的一个变体,格式为:

        \n

        [n]<<<word

    \n

    进行word波形符扩展、参数和变量扩展、\n命令替换、算术扩展和引号删除。\xc2\xa0\n不执行路径名扩展和分词。\xc2\xa0\n结果作为单个字符串提供,其中a\xc2\xa0 附加换行符 \n到 \xc2\xa0\xc2\xa0 其标准输入\n(或文件描述符n\xe2\x80\x82 n,如果指定)上的 \xc2\xa0 命令。

\n

\n

\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83(强调已添加)

\n

Bash 将此处的 a\xc2\xa0null 字符串转换为空行,而不是 \xc2\xa0EOF。

\n

如何修复它?

\n

明显的\xe2\x80\x94修改了循环逻辑:

\nwhile read dir   && [ "$dir" != "" ] \ndo\n\xc2\xa0 echo "HereDoc find: $dir"\ndone <<< "$(find /empty_directory -min深度 1 -max深度 1 -type d)"
\n如果读取到空行,则终止循环。

\n

同样明显的\xe2\x80\x94修改循环中的逻辑:

\n读取 dir\ndo\n\xc2\xa0    if [ "$dir" = "" ]; 然后继续;fi \n\xc2\xa0 echo "HereDoc find: $dir"\ndone <<< "$(find /empty_directory -min深度 1 -max深度 1 -type d)"
\n这会忽略空行(但不会\xe2\x80\x99t 终止循环)。

\n

也许更好的 \xe2\x80\x94 修改重定向:

\n读取 dir\ndo\n\xc2\xa0 echo "HereDoc find: $dir"\ndone < < (find /empty_directory -min深度 1 -max深度 1 -type d)
\n通过使用进程替换\n( )\n和\xc2\xa0简单重定向 ( )\xe2\x80\x82 而不是命令替换\n( )\n和这里的\xc2\xa0字符串 ( ),可以防止 Bash 添加\xc2 \xa0换行符。<(command)<$(command)<<<

\n

PS 请注意,您不需要 \xe2\x80\x99t 需要有一个 \xc2\xa0 分号 ( ;)\nat\xc2\xa0the\xc2\xa0a\xc2\xa0line 的末尾,就像您对 所做的那样while\xc2\xa0read\xc2\xa0dir

\n