如何修改sh/bash脚本以正确处理含非ASCII字符的文件?
含重音字符的文件名处理报错解决方案
我的tmpPdfFile.sh和tmpPdfFile1.sh脚本无法正确处理名为「6._ANbertà_di_scelta.docx.pdf」的文件,问题出在重音字符à上;但处理无重音的「6._ANbertata_di_scelta.docx.pdf」时正常。zip打包文件后问题仍存在,tar打包则无错误。已尝试bash和sh两种shell,以下是脚本代码及终端输出,求修改脚本以正确处理非ASCII字符。
脚本tmpPdfFile.sh:
#!/bin/bash -x echo "usage: $0 <pdf file (with extension)>" scriptName=`basename $0 .sh` filePath="$1" fileName=`basename $filePath .pdf` fileDir=`dirname $filePath` pdftk "${fileDir}/${fileName}.pdf" cat output "${fileDir}/${fileName}-stamp.pdf"
终端输出:
sartoret@linux-laptop:~/tools/bash$ diff tmpPdfFile.sh tmpPdfFile1.sh 1c1 < #!/bin/bash -x --- > #!/bin/sh -x 7c7 < pdftk "${fileDir}/${fileName}.pdf" cat output "${fileDir}/${fileName}-stamp.pdf" --- > pdftk "${fileDir}/${fileName}.pdf" cat output "${fileDir}/${fileName}-stamp1.pdf" sartoret@linux-laptop:~/tools/bash$ ./tmpPdfFile1.sh 6._ANbertà_di_scelta.docx.pdf + echo usage: ./tmpPdfFile1.sh <pdf file (with extension)> usage: ./tmpPdfFile1.sh <pdf file (with extension)> + basename ./tmpPdfFile1.sh .sh + scriptName=tmpPdfFile1 + filePath=6._ANbertà_di_scelta.docx.pdf + basename 6._ANbertà_di_scelta.docx.pdf .pdf + fileName=6._ANbertà_di_scelta.docx + dirname 6._ANbertà_di_scelta.docx.pdf + fileDir=. + pdftk ./6._ANbertà_di_scelta.docx.pdf cat output ./6._ANbertà_di_scelta.docx-stamp1.pdf Error: Unable to find file. Error: Failed to open input PDF file: ./6._ANberta??_di_scelta.docx.pdf Errors encountered. No output created. Done. Input errors, so no output created. sartoret@linux-laptop:~/tools/bash$ ./tmpPdfFile1.sh 6._ANber 6._ANbertata_di_scelta.docx.pdf 6._ANbertà_di_scelta.docx.pdf sartoret@linux-laptop:~/tools/bash$ ./tmpPdfFile1.sh 6._ANbertata_di_scelta.docx.pdf + echo usage: ./tmpPdfFile1.sh <pdf file (with extension)> usage: ./tmpPdfFile1.sh <pdf file (with extension)> + basename ./tmpPdfFile1.sh .sh + scriptName=tmpPdfFile1 + filePath=6._ANbertata_di_scelta.docx.pdf sartoret@linux-laptop:~/tools/bash$ ./tmpPdfFile.sh 6._ANbertata_di_scelta.docx.pdf + echo 'usage: ./tmpPdfFile.sh <pdf file (with extension)>' usage: ./tmpPdfFile.sh <pdf file (with extension)> ++ basename ./tmpPdfFile.sh .sh + scriptName=tmpPdfFile + filePath=6._ANbertata_di_scelta.docx.pdf ++ basename 6._ANbertata_di_scelta.docx.pdf .pdf + fileName=6._ANbertata_di_scelta.docx ++ dirname 6._ANbertata_di_scelta.docx.pdf + fileDir=. + pdftk ./6._ANbertata_di_scelta.docx.pdf cat output ./6._ANbertata_di_scelta.docx-stamp.pdf sartoret@linux-laptop:~/tools/bash$ ./tmpPdfFile.sh 6._ANberta 6._ANbertata_di_scelta.docx-stamp.pdf 6._ANbertata_di_scelta.docx.pdf 6._ANbertà_di_scelta.docx.pdf sartoret@linux-laptop:~/tools/bash$ ./tmpPdfFile.sh 6._ANberta 6._ANbertata_di_scelta.docx-stamp.pdf 6._ANbertata_di_scelta.docx.pdf 6._ANbertà_di_scelta.docx.pdf sartoret@linux-laptop:~/tools/bash$ ./tmpPdfFile.sh 6._ANbertà_di_scelta.docx.pdf + echo 'usage: ./tmpPdfFile.sh <pdf file (with extension)>' usage: ./tmpPdfFile.sh <pdf file (with extension)> ++ basename ./tmpPdfFile.sh .sh + scriptName=tmpPdfFile + filePath=$'6._ANberta\314\200_di_scelta.docx.pdf' ++ basename $'6._ANberta\314\200_di_scelta.docx.pdf' .pdf + fileName=$'6._ANberta\314\200_di_scelta.docx' ++ dirname $'6._ANberta\314\200_di_scelta.docx.pdf' + fileDir=. + pdftk $'./6._ANberta\314\200_di_scelta.docx.pdf' cat output $'./6._ANberta\314\200_di_scelta.docx-stamp.pdf' Error: Unable to find file. Error: Failed to open input PDF file: ./6._ANberta??_di_scelta.docx.pdf Errors encountered. No output created. Done. Input errors, so no output created. sartoret@linux-laptop:~/tools/bash$ ./tmpPdfFils1.sh 6._ANbertà_di_scelta.docx.pdf bash: ./tmpPdfFile.s1h: No such file or directory sartoret@linux-laptop:~/tools/bash sartoret@linux-laptop:~/tools/bash$ lst total 44K -rw-rw-r-- 1 sartoret sartoret 11K Jun 27 14:27 '6._ANberta'$'\314\200''_di_scelta.docx.pdf' -rw-rw-r-- 1 sartoret sartoret 11K Jun 27 14:27 6._ANbertata_di_scelta.docx.pdf -rwxrwxr-x 1 sartoret sartoret 1K Jun 27 14:32 tmpPdfFile1.sh -rwxrwxr-x 1 sartoret sartoret 1K Jun 27 14:32 tmpPdfFile.sh -rw-rw-r-- 1 sartoret sartoret 11K Jun 27 14:34 6._ANbertata_di_scelta.docx-stamp.pdf sartoret@linux-laptop:~/tools/bash$ ./tmpPdfFile1.sh '6._ANberta'$'\314\200''_di_scelta.docx.pdf' + echo usage: ./tmpPdfFile1.sh <pdf file (with extension)> usage: ./tmpPdfFile1.sh <pdf file (with extension)> + basename ./tmpPdfFile1.sh .sh + scriptName=tmpPdfFile1 + filePath=6._ANbertà_di_scelta.docx.pdf + basename 6._ANbertà_di_scelta.docx.pdf .pdf + fileName=6._ANbertà_di_scelta.docx + dirname 6._ANbertà_di_scelta.docx.pdf + fileDir=. + pdftk ./6._ANbertà_di_scelta.docx.pdf cat output ./6._ANbertà_di_scelta.docx-stamp1.pdf Error: Unable to find file. Error: Failed to open input PDF file: ./6._ANberta??_di_scelta.docx.pdf Errors encountered. No output created. Done. Input errors, so no output created. sartoret@linux-laptop:~/tools/bash$
解决方法
问题根源是系统locale未正确设置为UTF-8,导致非ASCII字符(如重音à)无法被正确解析,pdftk找不到对应文件。同时脚本中使用的旧版命令替换和未显式声明字符编码也会加剧问题。按以下步骤修改:
- 在脚本开头添加UTF-8编码声明
在shebang行之后添加,强制脚本使用UTF-8环境:
export LC_ALL=en_US.UTF-8 export LANG=en_US.UTF-8
- 改用bash内置参数替换替代
basename/dirname
bash的参数扩展更可靠,避免外部命令的编码问题:
- 获取文件名(不带路径和后缀):
fileName="${filePath%.pdf}" - 获取文件目录:
fileDir="${filePath%/*}",如果是当前目录则自动设为.
- 修改后的完整脚本
#!/bin/bash -x export LC_ALL=en_US.UTF-8 export LANG=en_US.UTF-8 echo "usage: $0 <pdf file (with extension)>" scriptName="${0%.sh}" scriptName="${scriptName##*/}" filePath="$1" # 处理文件名为空的情况 if [ -z "$filePath" ]; then exit 1 fi # 获取不带后缀的文件名 fileName="${filePath%.pdf}" # 获取文件目录,若为当前目录则设为. fileDir="${filePath%/*}" if [ "$fileDir" = "$filePath" ]; then fileDir="." fi pdftk "${fileDir}/${fileName##*/}.pdf" cat output "${fileDir}/${fileName##*/}-stamp.pdf"
- 验证系统locale设置
运行locale命令确认输出中所有LC_*和LANG均为UTF-8结尾,若不是则修改/etc/locale.conf或当前用户的.bashrc/.profile文件,添加:
LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
然后重新登录或执行source ~/.bashrc生效。
内容的提问来源于stack exchange,提问作者Flavio Sartoretto
相关产品推荐
相关产品推荐

