2

In my python script, I am trying to run a windows program that prints output. But I would like to redirect that output to a text file. I tried

     command = 'program' + arg1 + ' > temp.txt'
     subprocess.call(command)

Where program is my program name and arg1 is argument it takes. but it does not redirect the output to the text file It just prints that on the screen.

Can anyone help me how to do this? Thank you!

0

2 Answers 2

9

Pass a file object to the stdout parameter of subprocess.call():

with open('myoutfilename', 'w') as myoutfile:
    subprocess.call(cmd, stdout=myoutfile)
Sign up to request clarification or add additional context in comments.

7 Comments

+1 - get the library to do it for you. Also, the docs recommend you pass the program and arguments as a list so it can take care of the proper escaping for you - so the call we be something like subprocess.call(['program', arg1], stdout=myoutfile]).
@blair Indeed, cmd can be a list. The key point is use of the stdout parameter
@DavidHeffernan -- cmd must be a list if you're using program has arguments (and you're not using shell=True), but you're right about stdout being one of the key pieces to this.
Sure. Question is about redirect, hence the focus of the answer.
@mgilson: That's only true on Unix. On Windows, cmd can be a string, even if there are arguments—and, in fact, quoting the docs, "if args is a sequence, it will be converted to a string in a manner described in Converting an argument sequence to a string on Windows. This is because the underlying CreateProcess() operates on strings.`
|
5

You can use shell=True in subprocess.call

However, a (much) better way to do this would be:

command = ['program',arg1]
with open('temp.txt','w') as fout:
    subprocess.call(command,stdout=fout)

This removes the shell from the whole thing making it more system independent, and it also makes your program safe from "shell injection" attacks (consider arg1='argument; rm -rf ~' or whatever the windows equivalent is).

The context manager (with statement) is a good idea as it guarantees that your file object is properly flushed and closed when you leave the "context".

Note that it is important that if you're not using shell=True to a subprocess.Popen (or similar) class, you should pass the arguments as a list, not a string. Your code will be more robust that way. If you want to use a string, python provides a convenience function shlex.split to split a string into arguments the same way your shell would. e.g.:

 import subprocess
 import shlex
 with open('temp.txt','w') as fout:
     cmd = shlex.split('command argument1 argument2 "quoted argument3"'
     #cmd = ['command', 'argument1', 'argument2', 'quoted argument3']
     subprocess.call(cmd,stdout=fout)

4 Comments

Please do feel free to remove the version that doesn't use a context manager. There's no point leading people astray. I draw no pleasure in seeing such code perpetuated.
@DavidHeffernan -- Done. Though it was a bit of a challenge to re-work the wording to give you credit where it was due.
Well, thanks. But I deleted that. It's just best to see good and accurate answers.
@DavidHeffernan -- I noticed (and resisted to urge to repost it as a comment). In my line of work, credit means everything, so editing a post to absorb another's ideas seems wrong without proper "citation" or whatever. I've thought about deleting my answer as well, but it does add quite a bit to your answer so I haven't done so (but you're more than welcome to take whatever you like from my answer and add it to yours). Cheers, and I'm glad you got the checkmark :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.