Bash中使用find生成含空格路径数组的遍历异常问题
Bash处理含空格路径数组的问题解析及解决方法
问题场景
我能正常遍历包含空格的Bash字符串数组:
~ $ arr=( "/home/user/Images/three parts dirname/ccc.png" "/home/user/Images/three parts dirname/bbb.png" "/home/user/Images/three parts dirname/aaa.png" ) ~ $ for i in "${arr[@]}"; do echo "$i"; done
输出结果符合预期:
/home/user/Images/three parts dirname/ccc.png /home/user/Images/three parts dirname/bbb.png /home/user/Images/three parts dirname/aaa.png
但尝试用find命令生成数组时出现异常:
~ $ d="/home/user/Images/three parts name" ~ $ arr=( $(find -L "$d" -maxdepth 1 -iname '*.jp*g' -o -iname '*.png' -printf '"%p" ') )
单独执行find命令的输出是:
"/home/user/Images/three part name/ccc.png" "/home/user/Images/three part name/bbb.png" "/home/user/Images/three part name/aaa.png"
但遍历数组时,路径被空格拆分:
~ $ for i in "${arr[@]}"; do echo "$i"; done
输出结果:
"/home/user/Images/three parts name/ccc.png" "/home/user/Images/three parts name/bbb.png" "/home/user/Images/three parts name/aaa.png"
疑问:为什么数组项会被空格拆分,且双引号成为了字符串的一部分?
问题原因
Bash处理$(...)命令替换时,会先执行命令获取输出,再按照**默认的IFS(内部字段分隔符,默认包含空格、制表符、换行符)**对输出内容进行拆分,这个过程中会忽略输出里的引号语法——也就是说,你通过printf '"%p"'添加的双引号只是普通文本字符,不会被Bash当作路径的边界标识,所以空格依然会把完整路径拆分成多个数组元素。
比如find输出的"/home/user/Images/three parts name/ccc.png",会被Bash按空格拆分为"/home/user/Images/three"、parts、name/ccc.png"三个独立数组元素,这就是异常输出的根源。
正确解决方法
使用find的-print0选项输出以**空字符(\0)**分隔的路径(空字符是唯一不会出现在文件路径中的字符,能完美兼容含空格、特殊字符的路径),配合readarray命令读取数组,再完成排序和取前4项的操作,完整脚本如下:
# 读取所有符合条件的图片路径到数组,以空字符作为分隔符 readarray -d $'\0' TOT_IMAGES < <(find -L "$i" -maxdepth 1 \( -iname '*.jp*g' -o -iname '*.png' -o -iname '*.gif' -o -iname '*.tif*' \) -print0) # 临时将IFS设置为换行符,避免sort操作时拆分路径 IFS=$'\n' # 对数组内容排序并生成新数组 SORTED_IMAGES=($(sort <<<"${TOT_IMAGES[*]}")) # 取排序后的前4项生成新数组 TOP4_IMAGES=($(head -n4 <<<"${SORTED_IMAGES[*]}")) # 恢复默认IFS设置 unset IFS
内容的提问来源于stack exchange,提问作者dentex
相关产品推荐
相关产品推荐

