Bash中遍历find命令返回结果的正确实现方案求助
问题根因
- 原始写法直接捕获
find输出赋值给变量/数组时,Bash和zsh都会触发分词逻辑,换行符会被默认IFS(内部字段分隔符)当做分隔符拆分,路径带空格等特殊字符时还会出现不可预期的拆分错误 - 原始写法中
${releases[@]}将普通变量当做数组调用,语法本身不规范,Bash下虽然能勉强运行但不符合语法规则,zsh对语法检查更严格所以直接报错 - 原find语句中
-o逻辑优先级存在错误:find ... -type f -name "*.ear" -o -name "*.war"实际等效于( -type f -name "*.ear" ) -o ( -name "*.war" ),会匹配到非文件类型的.war/.ear对象
彻底优化方案
通用规范写法(兼容所有含特殊字符的路径,同时适配bash/zsh)
摒弃for x in $(find ...)的写法,统一用null分隔符的find结果处理方式,可100%解决路径拆分异常问题,同时ShellCheck检测全量通过。
方式1:直接遍历find结果(不需要预存到变量,性能最优)
#!/bin/bash # zsh兼容可加下一行注释掉的配置 # emulate -LR bash find "${DELIVERIES}" -maxdepth 1 -type d -name "*_delivery_33_SR*" -print0 | sort -z | while IFS= read -r -d '' d; do sr="${d##*_}" echo "Release $sr" # 不存在对应版本txt文件时再生成 if [ ! -e "${sr}.txt" ]; then # 修复原find的-o逻辑优先级问题,用括号包裹后缀匹配条件 find "${deliveries_path}"/*"${sr}"/ \( -name "*.ear" -o -name "*.war" \) -type f -print0 | sort -z | while IFS= read -r -d '' delivery_file; do basename "${delivery_file}" | tee -a "${sr}.txt" done fi echo done
方式2:预存结果到数组后遍历(需要多次使用结果时用)
#!/bin/bash # zsh兼容可加下一行注释掉的配置 # emulate -LR bash # 读取所有符合规则的目录到数组,mapfile要求bash 4.0+,主流发行版均支持 mapfile -d '' release_dirs < <(find "${DELIVERIES}" -maxdepth 1 -type d -name "*_delivery_33_SR*" -print0 | sort -z) # 遍历数组 for d in "${release_dirs[@]}"; do sr="${d##*_}" echo "Release $sr" # 读取交付文件到数组 mapfile -d '' deliveries < <(find "${deliveries_path}"/*"${sr}"/ \( -name "*.ear" -o -name "*.war" \) -type f -print0 | sort -z) if [ ! -e "${sr}.txt" ]; then for delivery_file in "${deliveries[@]}"; do basename "${delivery_file}" | tee -a "${sr}.txt" done fi echo done
批量修改旧脚本的规则
所有原脚本中for x in $(find ...); do ... done的结构,统一替换为上述find -print0 + read -d ''或者mapfile的结构即可一次性解决所有遍历异常问题。
内容的提问来源于stack exchange,提问作者Taavi Ansper
相关产品推荐
相关产品推荐

