MacOS下递归为每个文件创建对应文件夹并移入的脚本问题
解决MacOS下Shell脚本递归遍历文件的问题
核心问题根源
- 绝对不要用
ls -R的输出做循环遍历:ls -R的递归输出格式包含目录名(如subdir:),这些内容会被Shell的分词机制拆分成单个单词,导致循环中拿到的不是完整的文件路径,子目录下的文件根本无法被正确识别。 - 当目录结构复杂、文件数量较多时,
$(ls -R)会生成超长的参数列表,Shell需要一次性处理所有内容,直接导致脚本卡顿甚至挂起。 - 文件名包含空格、特殊字符(如
&、*)时,ls的输出会被错误拆分,完全破坏脚本逻辑。
正确的递归处理方案
1. 实现原需求:将每个文件移动到同名(不含后缀)目录中
使用find命令递归查找文件,结合子Shell批量处理,避免参数溢出和路径解析错误:
find . -type f -exec sh -c ' for file do # 提取不含后缀的文件名作为目录名 target_dir="${file%.*}" # 创建目录(-p确保父目录存在,已存在时不报错) mkdir -p "$target_dir" # 移动文件到目标目录 mv "$file" "$target_dir" done ' sh {} +
2. 实现测试需求:递归处理所有.rtf文件
方式一:直接用find的-exec参数
find . -type f -name "*.rtf" -exec echo "I do something with the file {}" \;
方式二:结合while read循环处理(适合复杂逻辑)
find . -type f -name "*.rtf" | while IFS= read -r rtf_file; do echo "I do something with the file $rtf_file" # 这里可以添加更多处理逻辑 done
IFS=:防止文件名开头/结尾的空格被截断-r:防止文件名中的反斜杠被Shell转义
补充说明
单独执行ls -R正常是因为它只是输出文本,但Shell处理$(ls -R)时会把所有输出拆分成独立的单词,完全丢失了文件路径的层级关系和完整性,这是Shell脚本遍历文件的典型误区,find才是递归处理文件的标准工具。
内容的提问来源于stack exchange,提问作者Eric VolkerLindell
相关产品推荐
相关产品推荐

