欢迎各位兄弟 发布技术文章
这里的技术是共享的
while IFS= read -r -d '' file; do
if [[ "$file" != /Library/* && "$file" != /System/Library/* ]]; then
files+=("$file")
fi
done < <(mdfind '((kMDItemFSName == "*AAAA*"cd) || (kMDItemFSName == "*BBBB*"cd) || (kMDItemFSName == "*CCCC*"cd) || (kMDItemFSName == "*DDDD*"cd) || (kMDItemFSName == "*EEEE*"cd)) && ((kMDItemFSName == "*.pdf"cd) || (kMDItemFSName == "*.ppt"cd) || (kMDItemFSName == "*.pptx"cd) || (kMDItemFSName == "*.key"cd) || (kMDItemFSName == "*.png"cd) || (kMDItemFSName == "*.jpg"cd) || (kMDItemFSName == "*.jpeg"cd))' -0)
与 while IFS= read -r -d '' file; do
if [[ "$file" != /Library/* && "$file" != /System/Library/* ]]; then
files+=("$file")
fi
done <<(mdfind '((kMDItemFSName == "*AAAA*"cd) || (kMDItemFSName == "*BBBB*"cd) || (kMDItemFSName == "*CCCC*"cd) || (kMDItemFSName == "*DDDD*"cd) || (kMDItemFSName == "*EEEE*"cd)) && ((kMDItemFSName == "*.pdf"cd) || (kMDItemFSName == "*.ppt"cd) || (kMDItemFSName == "*.pptx"cd) || (kMDItemFSName == "*.key"cd) || (kMDItemFSName == "*.png"cd) || (kMDItemFSName == "*.jpg"cd) || (kMDItemFSName == "*.jpeg"cd))' -0)
区别
这两个代码片段的区别在于 done 行末的 进程替换(Process Substitution) 语法写法不同:
bashdone < <(mdfind ... -0)
<(mdfind ... -0) 是一个 进程替换,它会将 mdfind 命令的输出作为一个临时文件描述符传递给 while 循环。
前面的 < 是标准输入重定向,表示从 <(mdfind ...) 的结果读取数据。
为什么正确?
<(command) 生成一个类似 /dev/fd/63 的文件描述符,供 while 循环逐行读取。
-0 选项让 mdfind 输出以 \0(NULL 字符)分隔,而 IFS= read -r -d '' 能够正确解析这种格式,避免文件名含空格或换行符时的解析错误。
bashdone <<(mdfind ... -0)
这里 <<( 缺少空格,使得 shell 解析错误。
可能被解释为:
<< 被当作 here-document(嵌入式文档) 的开始,但后面没有匹配的结束标记(如 EOF)。
或者,<<( 被当作一个无效的语法,直接报错(bash 会提示语法错误)。
正确形式:< <(command) → 先进程替换 <(...),再输入重定向 <,中间必须加空格。
错误形式:<<(...) → shell 无法识别,要么解析成 here-document(失败),要么直接报错。
这段代码的目的是:
用 mdfind 搜索 文件名包含 AAAA、BBBB、CCCC、DDDD 或 EEEE,且扩展名是 .pdf/.ppt/.pptx/.key/.png/.jpg/.jpeg 的文件。
排除系统目录:跳过 /Library/ 和 /System/Library/ 下的文件。
安全处理文件名:-0 和 IFS= read -r -d '' 确保即使文件名含空格或换行符也能正确读取。
如果你的代码写成 <<(...),bash 会报错,改为 < <(...) 即可正常运行。