1

After reading this question, I've been experimenting and using subprocess.call() in Python to run a command as if from the terminal. I've found it works quite well and I prefer it over os.system. I've run into a problem with cupsfilter, though. I'm trying to run this command on OS X, from Python:

cupsfilter -o cpi=10 PDFTestIn.txt 2>PDFTestError.txt >PDFTestOut.pdf

(I tried it, originally, with more than one option, but am limiting it to one option until I can get it working.)

I can run the command fine from the command line and from os.system, but I'm having trouble with this command in subprocess.call(). I've been experimenting in IDLE and cupsfilter does not work with this as other programs do. If I provide options in the form:

-o optionname=optionvalue

I always get error messages. I tried this:

import subprocess
import os
cmd = '/usr/sbin/cupsfilter'
args = ['-o cpi=10']
ifile='PDFTestIn.txt'
ofile='PDFTestOut.pdf'
efile='PDFTestError.txt'
cmdargs = [cmd] + args + [ifile]
with open(ofile, 'w') as pdfout, open(efile, 'w') as errout:
    subprocess.call(cmdargs, stdout=pdfout, stderr=errout)

When I do that, I get a return value of 1 from the last command. I check PDFTestError.txt for output and it reads:

cupsfilter: Unknown option " ".

I experimented by changing the 4th line to this:

args = ['-ocpi=10']

and I get this error:

cupsfilter: Unknown option "c".

Whatever character comes after the "-o" is seen as an option, and only that one letter is acknowledged, not the word (like "cpi"). Even though there are other options I can use besides "-o," I thought I'd try it without the "-o" just in case. When I do that, I get this error:

cupsfilter: Only one filename can be specified.

(And if I use only the command as an argument in the list passed to subprocess.call(), and still specify stdout and stderr, it works okay.)

Summary: When I use "-o" to provide an option for cupsfilter, in subprocess.call(), cupsfilter looks only at the next character, not the next word. If I have a space after "-o" as I would on the command line, it expects that space to be an option. If I leave the space out, it looks at the next character and not the next word. If I leave out "-o" it sees the option as another file name (as I'd expect).

But if I use the command line, above, from a terminal, or from os.system(), there's no problem at all.

Why won't this work with subprocess.call() and is there a way to correct that?

Community
  • 1
  • 1
Tango
  • 576
  • 1
  • 8
  • 26

1 Answers1

2

You need to separate each arg, '-o cpi=10' -> '-o', 'cpi=10':

subprocess.call([cmd,'-o','cpi=10',infile], stdout=pdfout, stderr=errout)
Padraic Cunningham
  • 160,756
  • 20
  • 201
  • 286
  • It seems I've just been lucky and that up until now, all the flags on commands didn't need args (like '--delete' on rsync). So this is the rule for all commands? If there's a space between a flag like '-o' and the value for it, use it as two arguments? In other words, this is the rule and not the exception, right? – Tango Feb 19 '15 at 21:44
  • @Tango, yes, when you pass args using a list when shell=False you need to split the command into individual args – Padraic Cunningham Feb 19 '15 at 21:46
  • 1
    On another note call will ignore non-zero exit statuses which may not be what you want, you can use `check_call` which will raise an error if there is a non-zero exit status – Padraic Cunningham Feb 19 '15 at 21:50
  • So "-x somefile" and "-y=true" both need to be passed in as 2 items in the array? (Rephrasing to be sure I understand.) I'm a little confused about call ignoring non-zero exit statuses. I see it will return the status, so do you mean a non-zero does not change call's behavior? – Tango Feb 19 '15 at 21:59
  • 1
    `"-x somefile" ` would be `"-x", "somefile" `. In relation to call I mean that if the process you well calling did not return a zero exit status, you would not know without either verifying the return code. i.e `c =call("ls")` `if c==0:al good`, where check_call will actually raise a calledProcessError – Padraic Cunningham Feb 19 '15 at 22:10
  • Thanks! One last question: if I have '-y=foobar' should that be ['y', 'foobar'] or ['y=foobar']? If there's an equals, should that be just one argument or two? – Tango Feb 19 '15 at 22:20
  • 1
    correct,if that is how you would run it from bash then that is a single arg. – Padraic Cunningham Feb 19 '15 at 22:20