Search code examples
pythonlinuxsubprocesspopen

Issue specifying parameters to 'pstops' in subprocess.Popen


Issuing this command from the command line:

pdftops -paper A4 -nocenter opf.pdf - | pstops "1:[email protected](0.5cm,13.5cm)" > test.ps

works fine. I tried to convert this to a parameter list for subprocess.Popen like this:

import subprocess as sp

path = 'opf.pdf'

ps = sp.Popen(
            ["pdftops",
             "-paper", "A4",
             "-nocenter",
             "{}".format(path),
             "-"],
            stdout = sp.PIPE)
pr = sp.Popen(
            ["pstops",
             "'1:[email protected](0.5cm,13.5cm)'"],
            stdin = ps.stdout,
            stdout = sp.PIPE)
sp.Popen(
            ["lpr"],
            stdin = pr.stdout )

where path is the filename - opf.pdf. This produces error, in the second Popen:

0x23f2dd0age specification error:
  pagespecs = [modulo:]spec
  spec      = [-]pageno[@scale][L|R|U|H|V][(xoff,yoff)][,spec|+spec]
                modulo >= 1, 0 <= pageno < modulo

(sic). I suspect the 0x23f2dd0 somehow replaced the 'P'. Anyway, I suspect the problem to be in the page spec 1:[email protected](0.5cm,13.5cm), so I tried with/without the single quotes, and with (escaped) double quotes. I even tried shlex.quote which produced a very exotic ''"'"'1:[email protected](0.5cm,13.5cm)'"'"'', but still the same error.

What is causing this?

EDIT As a last resource, I tried:

    os.system(("pdftops -paper A4 -nocenter {} - | "
               "pstops '1:[email protected](1cm,13.5cm)' | "
               "lpr").format(path))

which works perfectly. I'd still prefer the above Popen solution though.


Solution

  • Think about what the shell does with that argument (or use something like printf '%s\n' to get it to show you). We need to undo the shell quoting and replace it with Python quoting (which happens to be eerily similar):

    pr = sp.Popen(
                ["pstops",
                 "1:[email protected](0.5cm,13.5cm)"],
                stdin = ps.stdout,
                stdout = sp.PIPE)