如何在Bash中将带引号的文件名列表作为参数传递给其他脚本或命令
错误原因
你触发了Bash脚本处理带空格/特殊字符文件名时最常见的两个问题:
- 不要解析
ls的输出:ls是面向人类可读设计的工具,输出的引号、格式没有标准化的转义规则,用来获取文件名列表必然会出现边界问题 - 未加引号的命令替换/变量会触发分词:
$(ls -x -Q ...)输出的双引号是打印出来的字面字符,shell不会把它识别为参数边界的界定符,只会按空白字符拆分所有输出,所以本来的"file 01.pdf"会被拆成"file、01.pdf"两个独立参数,自然找不到对应文件。
正确解法:用数组存储文件名列表
不需要调用ls,直接用通配符匹配把结果存到Bash数组中,原生支持带空格、特殊字符的文件名:
# 将所有匹配规则的pdf文件存入数组,自动处理特殊文件名 pdf_files=( "file"*.pdf ) # 展开数组所有元素作为参数传给pdfunite,最后指定输出文件名 pdfunite "${pdf_files[@]}" "file output.pdf"
如果有更复杂的筛选需求(比如按修改时间排序、筛选子目录文件等),可以用find配合空字符分隔来实现安全的文件名读取:
# 开启nullglob,避免未匹配到文件时把通配符本身当成数组元素 shopt -s nullglob pdf_files=() # 按修改时间降序筛选当前目录下的file*.pdf while IFS= read -r -d '' file; do pdf_files+=( "$file" ) done < <(find . -maxdepth 1 -type f -name "file*.pdf" -printf "%T@ %p\0" | sort -z -nr | cut -z -d ' ' -f2-) pdfunite "${pdf_files[@]}" "file output.pdf"
写法原理
- 数组
${array[@]}在被双引号包裹时,会把每个数组元素作为独立的参数传递,不会触发分词 - 空字符
\0是类Unix系统中文件名唯一不允许出现的字符,用空字符作为分隔符传递文件名可以100%兼容所有合法文件名
内容的提问来源于stack exchange,提问作者ino
相关产品推荐
相关产品推荐

