bash 脚本中的内置“read -r”在 Mac 上的行为有所不同

Bri*_*sen 3 bash macintosh read

我有这个脚本:

#!/bin/bash
function main {
  while read -r file; do
    do_something "$file"
  done <<< $(find . -type f 2>/dev/null)
}
function do_something{
   echo file:$@
}
Run Code Online (Sandbox Code Playgroud)

在 Linux 上,它工作正常,但在 Mac(Bash 版本 5.2)上,它将找到的所有文件视为一项,并将整个字符串不带换行符传递到do_something. 如果我运行这个:

  while read -r file; do
    echo file:"$file"
  done <<< $(find . -type f 2>/dev/null)
Run Code Online (Sandbox Code Playgroud)

直接在 Mac 上的 Bash 终端中也可以正常工作。那么出了什么问题呢?

Sté*_*las 7

在旧版本的 bash 中,<<< $param$((arith))$(cmdsubst)where<<<是从 zsh 复制的这里字符串运算符,此类未加引号的扩展会受到$IFS-splitting 的影响,并且生成的单词会与空格连接起来,并将结果存储在构成重定向目标的临时文件中。

这个问题在 4.4 中得到了修复。请参阅CWRU/changelog 中的相应条目

2015-09-02

redir.c
- write_here_string:不要对此处字符串文档进行分词。bash 文档总是说这种情况不会发生,尽管 bash 多年来一直这样做,并且实现此处字符串的其他 shell 不执行任何分词。实际效果是 IFS 字符序列被折叠为空格。修复了 Clint Hepner <clint.hepner@gmail.com> 报告的错误

但 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)
Run Code Online (Sandbox Code Playgroud)

(进程替换,,,,,-r所有从ksh复制的都是在2.05b之前或在与2.05b相同的版本中引入的-u,所以应该在macos中可用)-d<<</bin/bash

由于 macos 已经预装了 zsh,你也可以切换到 zsh,然后编写:

for file (**/*(ND.)) something with $file
Run Code Online (Sandbox Code Playgroud)

也可以看看: