使用qpdf和Perl为PDF文件名添加页数前缀/后缀时脚本执行异常求助
兄弟,我先理清楚你的问题:你用sed提取PDF文件名的基础部分和括号里的数字时,简化脚本完全正常,但一结合qpdf(或者更复杂的逻辑),脚本就重复输出文件名三次,比如File (11).pdf连打三遍,对吧?
首先可以排除是sed正则的问题——毕竟你已经验证了简化版的提取逻辑没问题,大概率是循环的输入来源或者变量处理出了坑,我给你拆解几个常见问题和解决方案:
1. 别用ls *.pdf遍历文件!
虽然你设置了IFS=$'\n',但ls的输出在处理带空格/特殊字符的文件名时,很容易出各种意外(比如隐形的换行、拆分)。直接用通配符遍历才是稳妥的写法:
IFS=$'\n' # 直接遍历当前目录的所有PDF,不需要调用ls for i in *.pdf; do # 你的处理逻辑 done
这个小改动就能避免很多莫名其妙的循环重复问题。
2. 检查qpdf的输出是否干净
如果你的复杂脚本里用了qpdf获取页数(比如qpdf --show-npages "$i"),要确认它只输出数字,没有多余的警告、错误信息。如果qpdf输出了多行内容,会导致变量里混入换行,进而让后续逻辑重复执行。你可以单独跑一遍qpdf --show-npages "File (11).pdf"看看输出是不是只有一个数字。
3. 变量引用一定要加双引号!
你简化脚本里的printf $i其实有隐患,如果文件名里有空格或特殊字符,会被shell拆分。正确的写法是printf "%s\n" "$i",加双引号能保证变量被当成一个整体处理,避免意外拆分导致的重复输出。
给你一个调试后的完整示例(假设你要结合页数重命名)
如果你的需求是把File (11).pdf改成类似File_11_5.pdf(5是页数),可以用这个脚本:
# 遍历当前目录所有PDF文件 for pdf_file in *.pdf; do # 提取基础文件名(去掉括号数字和.pdf后缀) base_name=$(echo "$pdf_file" | sed -E 's/^(.*)( \([0-9]{1,4}\))(\.pdf)$/\1/') # 提取括号里的数字并去掉括号和空格 seq_num=$(echo "$pdf_file" | sed -E 's/^(.*)( \([0-9]{1,4}\))(\.pdf)$/\2/' | tr -d '() ') # 获取PDF页数(确保qpdf只输出数字) page_count=$(qpdf --show-npages "$pdf_file") # 重命名文件(按需调整格式) mv "$pdf_file" "${base_name}_${seq_num}_${page_count}.pdf" # 输出处理结果验证 echo "已处理:$pdf_file → ${base_name}_${seq_num}_${page_count}.pdf" done
快速定位问题的小技巧
你可以在复杂脚本的循环开头加一句echo "当前正在处理:$i",看看循环到底执行了几次,每次的$i是什么值。如果循环执行了三次,那就是遍历的元素多了;如果只执行一次但输出三次,那就是后面的printf或其他命令重复调用了。
备注:内容来源于stack exchange,提问作者Brian

