我有这个脚本:
#!/bin/bash
function main {
while read -r file; do
do_something "$file"
done <<< $(find . -type f 2>/dev/null)
}
function do_something{
echo file:$@
}
在 Linux 上,它工作正常,但在 Mac(Bash 版本 5.2)上,它将找到的所有文件视为一项,并将整个字符串不带换行符传递到do_something
.如果我运行这个:
while read -r file; do
echo file:"$file"
done <<< $(find . -type f 2>/dev/null)
直接在 Mac 上的 Bash 终端中也可以正常工作。那么出了什么问题呢?
答案1
在旧版本的 bash 中,<<< $param$((arith))$(cmdsubst)
where<<<
是从 zsh 复制的这里字符串运算符,此类未加引号的扩展会受到$IFS
-splitting 的影响,并且生成的单词会与空格连接起来,并将结果存储在构成重定向目标的临时文件中。
这个问题在 4.4 中得到了修复。看CWRU/变更日志中的相应条目:
2015-09-02
redir.c
- write_here_string:不要对此处字符串文档进行分词。 bash 文档总是说这种情况不会发生,尽管 bash 多年来一直这样做,并且实现此处字符串的其他 shell 不执行任何分词。实际效果是 IFS 字符序列被折叠为空格。修复了 Clint Hepner 报告的错误 <[电子邮件受保护]>
但 macOS 仍然使用古老版本的 bash。您可能在其他地方安装了较新的 bash,但据我所知,您的 shebang 中使用的 /bin/bash 是 3.2.x,而不是 5.2。
虽然引用 the可以解决该特定问题,但这里迭代的输出$(find...)
绝对是错误的方法。find
查看原因和正确的替代方案为什么循环查找的输出是不好的做法?
也就是说,如果您必须使用bash
循环(也可以在 中使用zsh
):
while IFS= read -rd '' -u3 file; do
something with "$file"
done 3< <(find . -type f -print0 2> /dev/null)
(进程替换,,,,,-r
所有从ksh复制的都是在-u
2.05b-d
之前或在与2.05b相同的版本中引入的<<<
,所以应该在macos中可用/bin/bash
)
由于 macos 已经预装了 zsh,你也可以切换到 zsh,然后编写:
for file (**/*(ND.)) something with $file
也可以看看: