Bash while循环中find命令为何忽略迭代器首个值?
问题根源:UTF-8 BOM 干扰了首行ID的读取
这个问题的核心原因几乎可以确定是你的IDs.csv文件开头带有UTF-8 字节顺序标记(BOM)。Windows下的很多编辑器(比如Excel、Notepad)保存UTF-8文件时会自动在开头添加BOM(十六进制为EF BB BF),而Bash不会自动忽略这个标记,导致第一次读取的$ID变量值并不是纯数字6518,而是6518(BOM字符+数字)——你可以通过cat -v IDs.csv查看首行,会看到开头的标记。
当find执行-iname '*(6518)'时,自然找不到匹配的目录;而后续行没有BOM,所以读取的ID是干净的数字,find就能正常匹配。哪怕你把6556移到首行,它也会被BOM污染,同样找不到对应目录。
验证方法
在脚本里添加一行打印ID的十六进制编码,就能确认BOM的存在:
while read -r ID do echo "$ID" echo "$ID" | hexdump -C # 新增这行查看十六进制编码 cd "`find . -iname "*($ID)"`" # ... 其余代码 done < IDs.csv
首行的输出会显示开头有ef bb bf,而后续行没有这个前缀。
解决方案
1. 直接去除CSV文件的BOM
用sed命令一次性清理首行的BOM:
sed -i '1s/^\xef\xbb\xbf//' IDs.csv
如果是macOS系统,需要加空参数:
sed -i '' '1s/^\xef\xbb\xbf//' IDs.csv
或者用Vim打开文件,执行:set nobomb后保存退出,也能彻底去除BOM。
2. 在脚本读取时过滤BOM
不想修改原文件的话,可以在读取前用sed过滤首行的BOM:
sed '1s/^\xef\xbb\xbf//' IDs.csv | while read -r ID do echo "$ID" DIR=$(find . -iname "*($ID)") if [ -n "$DIR" ]; then cd "$DIR" pwd cd - > /dev/null # 屏蔽cd -的路径输出,让日志更干净 else echo "Warning: No directory found for ID $ID" fi echo done
脚本优化建议
原脚本里直接用cd "find...``有两个隐患:
- 如果
find返回多个匹配目录,cd会报错; - 如果
find无返回,cd ''等价于cd $HOME(也就是你看到的pwd输出/home/Geremia)。
可以改成先把find结果存到变量,再做判断,同时用更安全的目录切换方式:
sed '1s/^\xef\xbb\xbf//' IDs.csv | while read -r ID do echo "$ID" # 只查找目录,避免匹配到同名文件 DIR=$(find . -iname "*($ID)" -type d) if [ -d "$DIR" ]; then pushd "$DIR" > /dev/null pwd popd > /dev/null else echo "No valid directory found for ID: $ID" fi echo done
用pushd/popd比cd+cd -更安全,尤其是在复杂脚本里不容易出错。
内容的提问来源于stack exchange,提问作者Geremia
相关产品推荐
相关产品推荐

