Shandeep Murugasamy
Shandeep Murugasamy

Reputation: 311

Reading and writing from and to different files in Python

I am trying to read the commands from "command.txt" file and want to redirect the output of this commands to "output.txt", contents of command.txt

ps -a
free

So far I came up with this code which for certain reason is not good and fails to execute.

import os
import sys
import subprocess
with open('output.txt', 'w') as out_file, open('command.txt', 'r') as in_file:
     for line in in_file:
         output = subprocess.Popen(line, stdout=subprocess.PIPE)
         print output
         out_file.write(output)

I am getting the below error:

Error:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7/Users/PythonTutorials/subprocess1.py
Traceback (most recent call last):
   File "/Users/shandeepkm/PythonTutorials/subprocess1.py", line 9, in <module>
   output = subprocess.Popen(line, stdout=subprocess.PIPE)
   File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 709, in __init__
errread, errwrite)
   File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1326, in _execute_child
raise child_exception
  OSError: [Errno 2] No such file or directory

Process finished with exit code 1

Could anyone please suggest appropriate python code for this task.

Upvotes: 1

Views: 138

Answers (2)

Hai Vu
Hai Vu

Reputation: 40723

Solution 1: Execute line by line

You can redirect to a file using the stdout parameter of Popen:

import subprocess
import shlex

with open('output.txt', 'wb') as outfile, open('command.txt') as infile:
    for line in infile:
        command = shlex.split(line)
        if not command:
            continue  # Skip blank lines
        try:
            process = subprocess.Popen(command, stdout=outfile)
            process.wait()
        except OSError:
            outfile.write('COMMAND ERROR: {}'.format(line))

In the code above, you redirect the output by pointing stdout to the output file's handle, no printing is needed. The code also guard against bad commands

Solution 2: Call the shell

If you are running under Linux or Mac, the following solution is simpler: by calling bash to execute the whole command.txt file and record the stdout and stderr. This should work under windows with cmd -c, but I don't have a Windows machine to try.

import subprocess

with open('output.txt', 'wb') as outfile:
    command = ['bash', 'command.txt']
    process = subprocess.Popen(command, stdout=outfile, stderr=outfile)
    process.wait()

Upvotes: 1

chrisaycock
chrisaycock

Reputation: 37930

I see two errors.

First, you have "command.txt" as the first line in your file. That definitely won't execute as a subprocess.

Also, your line

out_file.write(output)

needs to be tabbed under the for loop.


Now for the updated question:

The Popen constructor needs to take an array for the args. So instead of

'ps -a'

you need to pass

['ps', '-a']

Also, what gets returned from Popen isn't text. So altogether you need:

args = shlex.split(line)
output = subprocess.Popen(args, stdout=subprocess.PIPE).stdout.read()

Upvotes: 3

Related Questions