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.
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()
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()
Related
I am trying to read input from the user and store it in a variable by using subprocess.check_output in python2.7. But it shows up the error OSError: [Errno 2] No such file or directory when I try to run it. Also it is to be noted that I strictly want to use shell=False because of the security concerns.
I have tried subprocess.Popen and it doesnt work that way too.
I have tried to use sys.stdin = open('/dev/tty', 'r') and stdin=subprocess.PIPE but give the same error as above.
>>> import sys
>>> import subprocess
>>> sys.stdin = open('/dev/tty', 'r')
>>> cmd = ('read userinput && echo "$userinput"')
>>> confirmation = subprocess.check_output(cmd.split(), stdin=sys.stdin).rstrip()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/subprocess.py", line 567, in check_output
process = Popen(stdout=PIPE, *popenargs, **kwargs)
File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
The expected result is that it should ask for user input and store it to the confirmation variable
You are entering a shell command (read and echo are shell built-ins, and && is shell syntax), therefore you need shell=True. This is a single shell command, so you don't use the split. The parentheses around the command in python have no effect in this case:
import sys
import subprocess
sys.stdin = open('/dev/tty', 'r')
cmd = 'read userinput && echo "$userinput"'
confirmation = subprocess.check_output(cmd, stdin=sys.stdin, shell=True).rstrip()
print'****', confirmation
Gives:
$ python gash.py
hello
**** hello
I have to print bash history using subprocess package.
import subprocess
co = subprocess.Popen(['history'], stdout = subprocess.PIPE)
History = co.stdout.read()
print("----------History----------" + "\n" + History)
but they prompt an error
Traceback (most recent call last):
File "test.py", line 4, in <module>
co = subprocess.Popen(['history'], stdout = subprocess.PIPE)
File "/usr/lib/python2.7/subprocess.py", line 394, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1047, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Normally, you would need to add shell=True argument to your Popen call:
co = subprocess.Popen(['history'], shell=True, stdout = subprocess.PIPE)
Or to manually specify the shell you want to call.
co = subprocess.Popen(['/bin/bash', '-c', 'history'], stdout = subprocess.PIPE)
Unfortunately, in this particular case it won't help, because bash has empty history when used non-interactively.
A working solution would be to read ${HOME}/.bash_history manually.
Kit is correct, reading ~/.bash_history may be a better option:
from os.path import join, expanduser
with open(join(expanduser('~'), '.bash_history'), 'r') as f:
for line in f:
print(line)
I am trying to execute a python script that first creates a new file(if it does not exist) and then executes ci(on the newly created file) to create a rcs file with initial revision number. But when I run the script it asks me for description and ending with period '.'. I want this part to be automated with a default description and create the rcs file without user input. Any help would be much appreciated. Following is my code:
import os
import subprocesss
if os.path.isfile(location):
print "File already exists"
else:
f = open(location,'a')
subprocess.call(["ci", "-u", location])
f.close()
print "new file has been created"
I tried this and I am getting the following error:
import os
import subprocess
if os.path.isfile(location):
print "File already exists"
else:
f = open(location,'a')
cmd = "ci -u "+location
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
stdout_data = p.communicate(input='change\n.')[0]
f.close()
print "new file has been created"
Traceback (most recent call last):
File "testshell.py", line 15, in
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
File "/usr/local/pythonbrew/pythons/Python-2.7/lib/python2.7/subprocess.py", line 672, in init
errread, errwrite)
File "/usr/local/pythonbrew/pythons/Python-2.7/lib/python2.7/subprocess.py", line 1201, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
You can use subprocess.call's stdin argument to give the subprocess a file-like object to use as its standard input (what you would enter by hand).
The StringIO module contains a class called StringIO that offers a file-like interface to an in-memory string.
Combining these two pieces together will let you send a specific string to ci, as if the user had entered it manually
from StringIO import StringIO
import subprocess
...
subprocess.call(['command', 'with', 'args'], stdin=StringIO('StandardInput'))
Alternately, as CharlesDuffy suggests, you can use Popen and its communicate method:
import subprocess
proc = subprocess.Popen(['command', 'with', 'args'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate('StandardInput')
I am trying to save the result or function runcmd in the variable Result.
Here is what I have tried:
import subprocess
def runcmd(cmd):
x = subprocess.Popen(cmd, stdout=subprocess.PIPE)
Result = x.communicate(stdout)
return Result
runcmd("dir")
When I run ths code, I get this result:
Traceback (most recent call last):
File "C:\Python27\MyPython\MyCode.py", line 7, in <module>
runcmd("dir")
File "C:\Python27\MyPython\MyCode.py", line 4, in runcmd
x = subprocess.Popen(cmd, stdout=subprocess.PIPE)
File "C:\Python27\lib\subprocess.py", line 679, in __init__
errread, errwrite)
File "C:\Python27\lib\subprocess.py", line 893, in _execute_child
startupinfo)
WindowsError: [Error 2] The system cannot find the file specified
What could I do to fix this?
I think what you are looking for is os.listdir()
check out the os module for more info
an example:
>>> import os
>>> l = os.listdir()
>>> print (l)
['DLLs', 'Doc', 'google-python-exercises', 'include', 'Lib', 'libs', 'LICENSE.txt', 'NEWS.txt', 'python.exe', 'pythonw.e
xe', 'README.txt', 'tcl', 'Tools', 'VS2010Cmd.lnk']
>>>
You could also read the output into a list:
result = []
process = subprocess.Popen('dir',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE )
for line in process.stdout:
result.append(line)
errcode = process.returncode
for line in result:
print(line)
As far as I know, dir is a built in command of the shell in Windows and thus not a file available for execution as a program. Which is probably why subprocess.Popen cannot find it. But you can try adding shell=True to the Popen() construtor call like this:
def runcmd(cmd):
x = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
return x.communicate(stdout)
runcmd("dir")
If shell=True doesn't help, you're out of luck executing dir directly. But then you can make a .bat file and put a call to dir there instead, and then invoke that .bat file from Python instead.
btw also check out the PEP8!
P.S As Mark Ransom pointed out in a comment, you could just use ['cmd', '/c', 'dir'] as the value of cmd instead of the .bat hack if shell=True fails to fix the issue.
I have written a script that checks if an SVN Repo is up and running, the result is based on the return value.
import subprocess
url = " validurl"
def check_svn_status():
subprocess.call(['svn info'+url],shell=True)
def get_status():
subprocess.call('echo $?',shell=True)
def main():
check_svn_status()
get_status()
if __name__ == '__main__':
main()
The problem I'm facing is that if I change the url to something that does't exist I still get the return value as 0, but if I were to run this outside the script, i.e go to the terminal type svn info wrong url and then do a echo $? I get a return value of 1. But I can't re-create this in the python. Any guidelines ?
TraceBack after updating
Traceback (most recent call last):
File "svn_status.py", line 21, in <module>
main()
File "svn_status.py", line 15, in main
check_svn_status()
File "svn_status.py", line 8, in check_svn_status
p = sp.Popen(['svn info'], stdout=sp.PIPE, stderr=sp.PIPE)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 672, in __init__
errread, errwrite)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1202, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or director
y
Why your approach does not work:
You invoke two independent subshells. The second shell does not know of the first shell and therefore does not have any information about the returncode of the process that was executed in the first shell.
Solution:
Use the subprocess module, spawn your subprocess directly (not through a subshell) and retrieve the returncode. Help yourself by reading the documentation of the module: http://docs.python.org/library/subprocess.html
There are several ways to achieve your goal. One simple way could be:
import subprocess as sp
p = sp.Popen(['command', 'arg1', 'arg2'], stdout=sp.PIPE, stderr=sp.PIPE)
stdout, stderr = p.communicate()
returncode = p.returncode
This way, you don't go through a subshell (shell=False by default), which is the recommended approach for various reasons. You directly catch the returncode of the spawned subprocess and you have full access to the subprocess' standard output and standard error.
subprocess.call returns the retcode, just store the result of your subprocess.call(['svn info'+url],shell=True)
http://docs.python.org/library/subprocess.html