bashshelllateximagemagicktex

Infinite loop behavior from imagemagick when called from a shell script


I want to post-process pdf documents using imagemagic. I compile the documents themselves through Tex, using Lualatex. After compilation, a script I wrote automatically comes into play, which performs the actions I need and calls imagemagick through \ShellEscape. The problem is that imagemagick does not want to process documents if it receives an incoming file name through a variable. And here's what's strange: it does not return any errors, does not provide any information, and behaves as if it gets into an infinite loop. That is, after launching Lualatex I get a bunch of service information about the document compilation process, and then, when the execution reaches convert, the execution stops. The terminal does not freeze, I can type characters in it, but the task never completes. The task does not load the processor.

If I pass the name of the input file not through a variable, but directly enter it into the command, everything works.

Here's how I run Lualatex from the console:

rm -rf output-Pi/ && lualatex --shell-escape Pi.tex

Here's an example of a broken imagemagick call:

page_array='\"output-Pi/te@mp.com/Main Fu - Pi Lo.pdf[0]\"' &&
convert $(echo $page_array) merge.pdf

Here's an example of a working call:

convert \"output-Pi/te@mp.com/Main Fu - Pi Lo.pdf[0]\" merge.pdf

What do you think about this?

Of course, additional complexity is introduced by the fact that it is necessary to work through three interpreters: the Tex interpreter, which transfers the code to Lua, which transfers the code to Shell. Escaping special characters becomes a headache, but I can’t think of anything better.

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\"
    }")

Some decisions are dictated by the need to break through 3 interpreters and may seem excessive to you.


Solution

  • Useless echo. Quotes in the wrong place.

    page_array='output-Pi/te@mp.com/Main Fu - Pi Lo.pdf[0]'
    convert "$page_array" merge.pdf
    

    Of course, we don't know the context of this shell snippet, and if extra quoting/escaping is required.


    I suspect this is what you want

    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\" && 
        set -- \"${pdf_file_name}\".pdf* &&
        echo \"convert -density 300 $* -background  white -density 300 merge.pdf\" &&
        convert \"$@\" merge.pdf &&
        echo \"DONE\"
        }")
    

    I'm assuming that the files you're interested in all start with ${pdf_file_name}.pdf.

    I use set -- pattern to store the filenames in the positional parameters, the closest thing to an array that sh has.

    Then call convert with the positional parameters. I don't know that tool, so you may need to check if that's correct usage.