通过Shell脚本调用ImageMagick时出现无限循环问题求助
LuaLaTeX中通过ShellEscape调用ImageMagick的变量传递问题
问题现象
通过LuaLaTeX的\ShellEscape调用ImageMagick做PDF后处理时,用变量传递文件名会导致进程停滞:执行到convert命令时无报错、CPU无占用,但任务永远无法完成;直接在命令中写死文件名则一切正常。
复现命令
控制台执行的编译命令:
rm -rf output-Pi/ && lualatex --shell-escape Pi.tex
代码对比
异常调用(变量传递)
page_array='\"output-Pi/te@mp.com/Main Fu - Pi Lo.pdf[0]\"' && convert $(echo $page_array) merge.pdf
正常调用(直接写死文件名)
convert \"output-Pi/te@mp.com/Main Fu - Pi Lo.pdf[0]\" merge.pdf
复杂场景背景
由于需要经过TeX解释器→Lua→Shell三层解释器转义,特殊字符处理极其繁琐,相关Lua代码片段如下:
tex.sprint("\\ShellEscape{% main_dir=\"output-\\jobname\" && email_dir=\"${main_dir}/\", ii[1]:gsub(\",\", \"\"), \"\" && pdf_file_name=\"${email_dir}/Main Fu - Pi Lo\" && mkdir -p $main_dir && mkdir -p $email_dir && lualatex --jobname=\"${pdf_file_name}\" \"\\gdef\\string\\conditionmacro{", t[i], "}\\string\\input\\space\\jobname\" && pdf_file_page=$(identify \"${pdf_file_name}.pdf\" 2>/dev/null | wc -l | tr -d ' ') && page=0 && quote='\"' && while [ $page -lt $pdf_file_page ] ; do page=$(($page + 1)) && page2=$(($page-1)) && echo \"${page2} - ${pdf_file_name}\" && pdf_file_name2=$(echo $pdf_file_name | sed 's/ /\\\\\\ /g') && page_array=\"${page_array}${quote}${pdf_file_name}.pdf[${page2}]\" && page_array=$(echo \"${page_array}${quote} \") ; done && echo \"------------------------------------\" && echo $page_array && echo $SHELL && page_array='\"output-Pi/te@mp.com/Main Fu - Pi Lo.pdf[0]\"' && echo \"convert -density 300 $(echo $page_array) -background white -density 300 merge.pdf\" && convert $(echo $page_array) merge.pdf && echo \"DONE\" }")
解决办法
避免多余的变量展开:Shell中直接使用变量即可保留空格和引号,无需用
$(echo $page_array)处理,修改异常调用为:page_array='"output-Pi/te@mp.com/Main Fu - Pi Lo.pdf[0]"' && convert $page_array merge.pdf改用Shell数组存储路径:多页面场景下,用数组替代字符串拼接,彻底规避空格、特殊字符的转义问题:
# 初始化数组 page_array=() # 循环添加页面路径 page_array+=("${pdf_file_name}.pdf[${page2}]") # 调用convert时直接传递数组 convert "${page_array[@]}" merge.pdf简化三层转义逻辑:在Lua中编写辅助函数统一转义Shell特殊字符,减少手动嵌套转义的出错概率:
function shell_escape(s) return "'" .. s:gsub("'", "'\\''") .. "'" end生成Shell命令时用该函数处理文件名:
local escaped_pdf = shell_escape(pdf_file_name .. ".pdf[" .. page2 .. "]") tex.sprint("page_array+=(" .. escaped_pdf .. ")")开启调试模式定位问题:在Shell命令开头添加
set -x,可以查看实际执行的命令内容,快速定位转义错误:tex.sprint("\\ShellEscape{% set -x # 其余命令... }")
内容的提问来源于stack exchange,提问作者Nikulok
相关产品推荐
相关产品推荐

