0

I am trying to run the bash command pdfcrack in Python on a remote server. This is my code:

bashCommand = "pdfcrack -f pdf123.pdf > myoutput.txt"
import subprocess
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()

I, however, get the following error message:

Non-option argument myoutput2.txt
Error: file > not found

Can anybody see my mistake?

1
  • 1
    It looks like pdfcrack thinks that > is also a filename. Try writing to a file with python using the stdout Commented Jan 13, 2017 at 18:17

3 Answers 3

1

The first argument to Popen is a list containing the command name and its arguments. > is not an argument to the command, though; it is shell syntax. You could simply pass the entire line to Popen and instruct it to use the shell to execute it:

process = subprocess.Popen(bashCommand, shell=True)

(Note that since you are redirecting the output of the command to a file, though, there is no reason to set its standard output to a pipe, because there will be nothing to read.)

A better solution, though, is to let Python handle the redirection.

process = subprocess.Popen(['pdfcrack', '-f', 'pdf123.pdf'], stdout=subprocess.PIPE)
with open('myoutput.txt', 'w') as fh:
    for line in process.stdout:
        fh.write(line)
        # Do whatever else you want with line

Also, don't use str.split as a replacement for the shell's word splitting. A valid command line like pdfcrack -f "foo bar.pdf" would be split into the incorrect list ['pdfcrack', '-f', '"foo', 'bar.pdf"'], rather than the correct list ['pdfcrack', '-f', 'foo bar.pdf'].

Sign up to request clarification or add additional context in comments.

3 Comments

you could use shlex.split() if the command line comes exclusively as a string. Quotes are then taken into account. but yeah argument list is better.
The first sentence of the documentation makes me run away from that module: "The shlex class makes it easy to write lexical analyzers for simple syntaxes resembling that of the Unix shell." Besides, I've never seen the need to encode your argument list into a string only to break it back into a list.
that could be handy when reading from a configuration file or when creating your own shell for instance. Probably not here.
1

> is interpreted by shell, but not valid otherwise.

So, that would work (don't split, use as-is):

process = subprocess.Popen(bashCommand, shell=True)

(and stdout=subprocess.PIPE isn't useful since all output is redirected to the output file)

But it could be better with native python for redirection to output file and passing arguments as list (handles quote protection if needed)

with open("myoutput.txt","w") as f:
    process = subprocess.Popen(["pdfcrack","-f","pdf123.pdf"], stdout=subprocess.PIPE)
    f.write(process.read())
    process.wait()

2 Comments

You don't want to mix shell=True with a list argument.
oh, right, changing that. I wouldn't do like that anyway, second solution is better.
0

Your mistake is > in command.

It doesn't treat this as redirection to file because normally bash does it and now you run it without using bash.

Try with shell=True if you whan to use bash. And then you don't have to split command into list.

subprocess.Popen("pdfcrack -f pdf123.pdf > myoutput.txt", shell=True)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.