This question already has answers here:
Closed 13 years ago.
Possible Duplicates:
How to get output from subprocess.Popen()
Retrieving the output of subprocess.call()
Here is my question. I have an executable called device_console. The device_console provides a command line interface to a device. In device_console, four commands can be run: status, list, clear and exit. Each command produces an output. As an example:
[asdfgf#localhost ~]$ device_console
device_console> list
File A
File B
device_console> status
Status: OK
device_console> clear
All files cleared
device_console> list
device_console> exit
[asdfgf#localhost ~]$
As part of testing, I want to get the output of each command. I want to use Python for it. I am looking at Python's subprocess, but somehow I am unable to put them together. Can you please help?
Use the subprocess module. Example:
import subprocess
# Open the subprocess
proc = subprocess.open('device_console', stdin=subprocess.PIPE, stdout.subprocess.PIPE)
# Write a command
proc.stdin.write('list\n')
# Read the results back -- this will block until a line of input is received
listing = proc.stdout.readline()
# When you're done, close the input stream so the subprocess knows to exit
proc.stdin.close()
# Wait for subprocess to exit (optional) and get its exit status
exit_status = proc.wait()
it sounds like you want something more like 'Expect'.
check out Pexpect
"Pexpect is a pure Python module that
makes Python a better tool for
controlling and automating other
programs. Pexpect is similar to the
Don Libes Expect system, but Pexpect
as a different interface that is
easier to understand. Pexpect is
basically a pattern matching system.
It runs programs and watches output.
When output matches a given pattern
Pexpect can respond as if a human were
typing responses."
Related
Normally you can automate answers to an interactive prompt by piping stdin:
import subprocess as sp
cmd = 'rpmbuild --sign --buildroot {}/BUILDROOT -bb {}'.format(TMPDIR, specfile)
p = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE, stdin=sp.PIPE, universal_newline=True, shell=True)
for out in p.communicate(input='my gpg passphrase\n'):
print(out)
For whatever reason, this is not working for me. I've tried writing to p.stdin, before executing p.communicate(), I've tried flushing the buffer, I've tried using bytes without universal_newlines=True, I've hard coded things, etc. In all scenarios, the command is executed and hangs on:
Enter pass phrase:
My first hunch was that stdin was not the correct file descriptor and that rpmbuild was internally calling a gpg command, and maybe my input isn't piped. But when I do p.stdin.close() I get an OSerror about subprocess trying to write to the closed descriptor.
What is the rpmbuild command doing to stdin that prevents me from writing to it?
Is there a hack I can do? I tried echo "my passphrase" | rpmbuild .... as the command but that doesn't work.
I know I can do something with gpg like command and sign packages without a passphrase but I kind of want to avoid that.
EDIT:
After some more reading, I realize this is issue is common to commands that require password input, typically using a form of getpass.
I see a solution would be to use a library like pexpect, but I want something from the standard library. I am going to keep looking, but I think maybe i can try writing to something similar /dev/tty.
rpm uses getpass(3) which reopens /dev/tty.
There are 2 approaches to automating:
1) create a pseudotty
2) (linux) find the reopened file descriptor in /proc
If scripting, expect(1) has (or had) a short example with pseudotty's that can be used.
I am running this python code from the command line:
# run on command line as: python firstscript.py
import sys, subprocess
pid = subprocess.Popen([sys.executable, 'secondscript.py']).pid
sys.exit()
Unfortunately I can't get it to exit all the way to the command line. If I hit the enter key (on OSX) it will finally exit. Is there a way to force the script to exit all the way to the command line without lingering in this weird limbo state? Also, I don't want to redirect stdout or stderr anywhere else because if I do, I lose the ability in secondscript.py to log output to a log file.
Thanks for the help.
The changes below worked for me:
# run on command line as: python firstscript.py
import sys, subprocess
process = subprocess.Popen([sys.executable, 'secondscript.py'])
output = process.communicate()[0]
You seem to be asking if there is a better way to do this. Check out check_output. I have always found it much more convenient and fool proof compared to the lower level stuff in subprocess.
I am new to python. I would like to run a "EDA tool" from python interactively.
Here are the steps I wanted to follow:
Start the tool
Run the first command in the tool
Check for the first command output or parse (in the main pyton) script
Run the second command
Parse the output in python script
[...]
x. Exit the tool
x+1. Do some post processing in main pyhon script
I am looking for some information or pointers related to it so that I can read on my own.
This depends on what you mean by a "command". Is each command a separate process (in the operating-systems definition of that word)? If so, it sounds like you need the subprocess module.
import subprocess
execNamePlusArgs = [ 'ls', '-l' ] # unix-like (i.e. non-Windows) example
sp = subprocess.Popen( execNamePlusArgs, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
stdout, stderr = sp.communicate() # this blocks until the process terminates
print( stdout )
If you don't want it to block until termination (e.g. if you want to feed the subprocess line-by-line input and examine its output line by line) then you would define stdin=subprocess.PIPE as well and then, instead of communicate, you might use calls to sp.stdin.writeline(whatever), sp.stdout.readline() and sp.stderr.readline()
You should look into using something like python-fabric
It allows you to use higher level language constructs such as context managers and makes the shell more usable with python in general.
Example usage:
from fabric.operations import local
from fabric.context_managers import lcd
with lcd(".."): # Prefix all commands with 'cd.. &&'
ls = local('ls',capture=True) # Run 'ls' command and put result into variable
print ls
>>>
[localhost] local: ls
Eigene Bilder
Eigene Musik
Eigene Videos
SynKernelDiag2015-11-07_10-01-13.log
desktop.ini
foo
scripts
This question already has answers here:
Linux command-line call not returning what it should from os.system?
(10 answers)
Closed 7 years ago.
I was experimenting with getting python to interact with my terminal, and i tried the following script, and it returned 0, when i expected it to show the contents of the current directory:
>>> import os
>>> os.system("ls")
0
Why does it do this? (note this is a mac command, as i'm on a mac)
0 is the exit status of ls when it completes successfully.
If you want to capture a list of filenames, you want its stdout, not its exit status. os.system() doesn't return that.
I'd suggest:
import subprocess
output = subprocess.check_output(["ls"]) # will raise an exception if ls fails
Well, that's how the os.system function works (From the python doc):
On Unix, the return value is the exit status of the process encoded in the format specified for wait()
In this case 0 is the return value of the ls command which means that the command was successful. The system function does not capture the stdout or stderr.
If you want to capture them, please use the subprocess module.
It returns 0 as that is the exit code for the command (meaning it exited cleanly).
If you want the results from a command, I would recommend using the subprocess module (https://docs.python.org/2/library/subprocess.html#module-subprocess).
It is the ls exit code.
If you execute an invalid command, the response will be probably something different than zero.
>>> os.system("ls -wk")
ls: invalid line width: k
512
I'm using the OS.System command to call a python script.
example:
OS.System("call jython script.py")
In the script I'm calling, the following command is present:
x = raw_input("Waiting for input")
If I run script.py from the command line I can input data no problem, if I run it via the automated approach I get an EOFError. I've read in the past that this happens because the system expects a computer to be running it and therefore could never receive input data in this way.
So the question is how can I get python to wait for user input while being run in an automated way?
The problem is the way you run your child script. Since you use os.system() the script's input channel is closed immediately and the raw_input() prompt hits an EOF (end of file). And even if that didn't happen, you wouldn't have a way to actually send some input text to the child as I assume you'd want given that you are using raw_input().
You should use the subprocess module instead.
import subprocess
from subprocess import PIPE
p = subprocess.Popen(["jython", "script.py"], stdin=PIPE, stdout=PIPE)
print p.communicate("My input")
Your question is a bit unclear. What is the process calling your Python script and how is it being run? If the parent process has no standard input, the child won't have it either.