3

I'm having problem with string redirection and python with a shell Ghostscript command.

There is NP executing this:

subprocess.call(["gs", "-q","-dBATCH", "-dNOPAUSE","-sDEVICE=bbox", "input.pdf"])

But I get an error adding 2>&1:

subprocess.call(["gs", "-q","-dBATCH", "-dNOPAUSE","-sDEVICE=bbox", "input.pdf","2>&1"])

Or:

subprocess.call(["gs", "-q","-dBATCH", "-dNOPAUSE","-sDEVICE=bbox", "input.pdf","2>&1",">/dev/null"])

I want to use 2>&1 to apply 'grep'.

Sample of the error:

Error: /undefinedfilename in (2>&1) Operand stack:

Execution stack: %interp_exit .runexec2 --nostringval--
--nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- false 1 %stopped_push Dictionary stack: --dict:1156/1684(ro)(G)--
--dict:1/20(G)-- --dict:77/200(L)-- Current allocation mode is local Last OS error: 2 GPL Ghostscript 9.05: Unrecoverable error, exit code 1 1

Still remains unsolved how to execute a command like:

subprocess.call("gs -q -dBATCH -dNOPAUSE -sDEVICE=bbox input.pdf 2>&1
| egrep -v HiResBoundingBox | egrep -o "[0-9]{1,}",shell=True)
Kurt Pfeifle
  • 86,724
  • 23
  • 248
  • 345
jacktrades
  • 7,224
  • 13
  • 56
  • 83
  • The "unsolved" command you are trying to execute doesn't work? Or it doesn't work if you try to do it with `shell=False`? (it seems to me that it should work with `shell=True`) – mgilson May 04 '12 at 16:31
  • Your initial version had a typo: it had '2<&1' where '2>&1' should have been (at 2 different locations). Check if this was the cause of the error you did see. Otherwise, it may be Python (which I'm not overly familiar with) not supporting this kind of redirection (or requiring a different syntax). – Kurt Pfeifle May 04 '12 at 16:35
  • Read up about Ghostscript's *'Interacting with Pipes'* here: http://git.ghostscript.com/?p=ghostpdl.git;a=blob_plain;f=gs/doc/Use.htm;hb=HEAD#Pipes - It may help you to find a workaround. – Kurt Pfeifle May 04 '12 at 16:40
  • Sorry for the typo. Still the last command does not work even with shell=False. Thanks. – jacktrades May 04 '12 at 16:43

1 Answers1

3

It's because you're passing the arguments as a list. When you pass the arguments as an iterable, each piece is passed to the spawned process (in this case, gs is complaining that it doesn't know what to do with 2>&1...) You'd probably get the same message if you typed:

gs -q -dBATCH -dNOPAUSE -sDEVICE=bbox input.pdf '2>&1' 

in a shell.

subprocess.call("gs -q -dBATCH -dNOPAUSE -sDEVICE=bbox input.pdf 2>&1",shell=True)

will do what you want -- or 'better'...

import sys
subprocess.call(["gs", "-q", "-dBATCH", "-dNOPAUSE", "-sDEVICE=bbox", "input.pdf"],stderr=sys.stdout)

(better because it sidesteps the security issues with shell=True)

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • Thanks. I would also want to use `subprocess.Popen` but according to this [answer](http://stackoverflow.com/a/2502883/1341526), a list should be used. – jacktrades May 04 '12 at 15:44
  • @jacktrades `subprocess.call` is really just a thin wrapper around `subprocess.Popen`. Lists generally should be used because they avoid the `shell=True` insecurities -- but then you have to avoid common shell constructs that we all love (like redirection). -- As for the link you posted, `Popen` can invoke a shell if you pass it `shell=True`, it just doesn't by default (same with `call`) – mgilson May 04 '12 at 15:46
  • Thanks. Your 'better' suggestion is not useful since the final command I want to use includes 'grep', and without 2<&1 grep does not work. `gs -q -dBATCH -dNOPAUSE -sDEVICE=bbox input.pdf 2>&1 >/dev/null | egrep -v HiResBoundingBox | egrep -o "[0-9]{1,}"` – jacktrades May 04 '12 at 15:50
  • @jacktrades You can do pipelines also ( http://docs.python.org/library/subprocess.html#replacing-shell-pipeline ). You'd might need to do a little work to mix stdout and stderr (unless you really only need stderr). – mgilson May 04 '12 at 15:56
  • Thanks, I'll wait if something more direct comes up. – jacktrades May 04 '12 at 16:12
  • 2
    I don't think you're going to get much better; these are _the_ two methods of calling processes. You either ask the shell to interpret a shell-like command line with `shell=True`, or you invoke each process yourself giving it its argument list and manage their I/O streams yourself. If you're not adding arbitrary user input to your list of arguments, it's probably okay to use the shell to achieve what you want—the shell becomes dangerous primarily when you're inserting user-supplied strings into the command line. – Mattie May 04 '12 at 16:41