创建一个空目录,然后运行以下代码:
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)"
这是输出:
-----
HereDoc find:
换句话说,第二个循环使用空变量执行一次。
为什么会这样?如何才能使第二个循环正常运行,并且在没有找到要循环的目录时不运行?
答案1
发生了什么?
我知道您正在尝试解决特定问题,但调试的首要规则之一是简化场景。如果我们这样做
$ sleep 1 | read x
$ echo "$?"
1
$ read x <<< $(sleep 1)
$ echo "$?"
0
我们看到read
来自空管道的 a 失败,但 read
来自 null 字符串的 a 成功(读取空值)。这就是你所看到的。
它的拼写是重击(1):
这里是字符串
Here 文档的一个变体,格式为:
[n]<<<word
这
word
进行波形符扩展、参数和变量扩展、命令替换、算术扩展和引号删除。不执行路径名扩展和分词。结果作为单个字符串提供,附加换行符, 到其标准输入(或文件描述符)上的命令n
如果n
已指定)。
(强调已添加)
Bash 将此处的 null 字符串转换为空行,而不是 EOF。
如何修复它?
显而易见的是——修改循环逻辑:
读取目录时 && [“$dir”!=“”] 做 echo "HereDoc 查找:$dir" 完成 <<< "$(find /empty_directory -min深度 1 -max深度 1 -type d)"如果读取到空行,则终止循环。
同样明显的是——修改逻辑在循环:
读取目录时 做 如果[“$dir”=“”];然后继续;菲 echo "HereDoc 查找:$dir" 完成 <<< "$(find /empty_directory -min深度 1 -max深度 1 -type d)"这会忽略空行(但不会终止循环)。
也许更好——修改重定向:
读取目录时 做 echo "HereDoc 查找:$dir" 完毕<<(查找 /empty_directory -min深度 1 -max深度 1 -类型 d)通过使用进程替换 ( ) 和简单重定向 (
<(command)
<
) 而不是命令替换 ( ) 和此处的字符串 ($(command)
<<<
),您可以阻止 Bash 添加换行符。
PS 请注意,您不需要;
像使用 那样在行尾添加分号 () while read dir
。