I'm building a Flask application that allows a user to execute python scripts and see its output in the body of the http response.
The following code works but I'm not able to return the output of the child process to the father's in order to return a html response with the script output.
For example, in the app.py file I use the following code to run a subprocess that executes the client requested python script.
#app.route('/scripts/<script_name>')
def exec_script(script_name):
if os.path.isfile(os.path.join(app.config['SCRIPT_FOLDER'], script_name)):
result = subprocess.run(['python', os.path.join(app.config['SCRIPT_FOLDER'], script_name)], stdout=subprocess.PIPE, cwd=app.config['SCRIPT_FOLDER'])
print(result.stdout.decode('utf-8'))
# return HTML_PAGE
Let's suppose that the requested script example.pyspawns a process that executes a shell command, I'm not able to pass the output of the shell command to the process that was run in app.py
example.py
import subprocess
result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
I guess that the reason why this is happening is that the process created in app.py is completed before the one created in the script. Is there a way to redirect the shell command output to the main application?
You can use subprocess.check_output
example:
result = subprocess.check_output(['ls', '-l'])
if result is not None:
print(result.decode('utf-8'))
Otherwise you can also try with subprocess.Popen:
result = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE).communicate()[0]
or:
p = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result, err = p.communicate()
print(result.decode('utf-8'))
Related
Hey i'm trying to run a shell Script with python using the Following lines:
import subprocess
shellscript = subprocess.Popen(["displaySoftware.sh"], stdin=subprocess.PIPE)
shellscript.stdin.write("yes\n")
shellscript.stdin.close()
returncode = shellscript.wait()
But when I run the Program it says that it can't find the .sh file.
Your command is missing "sh", you have to pass "shell=True" and "yes\n" has to be encoded.
Your sample code should look like this:
import subprocess
shellscript = subprocess.Popen(["sh displaySoftware.sh"], shell=True, stdin=subprocess.PIPE )
shellscript.stdin.write('yes\n'.encode("utf-8"))
shellscript.stdin.close()
returncode = shellscript.wait()
This method might be better:
import subprocess
shellscript = subprocess.Popen(["displaySoftware.sh"], shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
returncode = shellscript.communicate(input='yes\n'.encode())[0]
print(returncode)
When running this on my machine the "displaySoftware.sh" script, that is in the same directory as the python script, is successfully executed.
I want code like this:
process=run('2.PY')
whilt ScriptRunning(process):
txt=input()
output=pass(process,txt)
print(output )
I have two scripts
Script 1.py
Script 2.py
I want to run script 2 with script 1. between them passing parameter.
My second script has the ability to stay in zombie mode and wait for input.
I tried with the subprocess module, but after execution, it does not wait to receive input and completes the process.
out put :
import subprocess
cmd = 'python3 TC-Bot/src/run.py'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
out, err = p.communicate()
if not err:
result = out.split('\n')
for lin in result:
if not lin.startswith('#'):
print(lin)
else:
print(err)
I have a python (v3.3) script that runs other shell scripts. My python script also prints message like "About to run script X" and "Done running script X".
When I run my script I'm getting all the output of the shell scripts separate from my print statements. I see something like this:
All of script X's output
All of script Y's output
All of script Z's output
About to run script X
Done running script X
About to run script Y
Done running script Y
About to run script Z
Done running script Z
My code that runs the shell scripts looks like this:
print( "running command: " + cmnd )
ret_code = subprocess.call( cmnd, shell=True )
print( "done running command")
I wrote a basic test script and do *not* see this behaviour. This code does what I would expect:
print("calling")
ret_code = subprocess.call("/bin/ls -la", shell=True )
print("back")
Any idea on why the output is not interleaved?
Thanks. This works but has one limitation - you can't see any output until after the command completes. I found an answer from another question (here) that uses popen but also lets me see the output in real time. Here's what I ended up with this:
import subprocess
import sys
cmd = ['/media/sf_git/test-automation/src/SalesVision/mswm/shell_test.sh', '4', '2']
print('running command: "{0}"'.format(cmd)) # output the command.
# Here, we join the STDERR of the application with the STDOUT of the application.
process = subprocess.Popen(cmd, bufsize=1, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in iter(process.stdout.readline, ''):
line = line.replace('\n', '')
print(line)
sys.stdout.flush()
process.wait() # Wait for the underlying process to complete.
errcode = process.returncode # Harvest its returncode, if needed.
print( 'Script ended with return code of: ' + str(errcode) )
This uses Popen and allows me to see the progress of the called script.
It has to do with STDOUT and STDERR buffering. You should be using subprocess.Popen to redirect STDOUT and STDERR from your child process into your application. Then, as needed, output them. Example:
import subprocess
cmd = ['ls', '-la']
print('running command: "{0}"'.format(cmd)) # output the command.
# Here, we join the STDERR of the application with the STDOUT of the application.
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
process.wait() # Wait for the underlying process to complete.
out, err = process.communicate() # Capture what it outputted on STDOUT and STDERR
errcode = process.returncode # Harvest its returncode, if needed.
print(out)
print('done running command')
Additionally, I wouldn't use shell = True unless it's really required. It forces subprocess to fire up a whole shell environment just to run a command. It's usually better to inject directly into the env parameter of Popen.
Here's an example of the shell script:
python command_name.py --shell positional_arg1 positional_arg2 --option optional_arg1 --True_flag
I just want to be able to call this from a python script so I can loop through the script, changing different parameters through each loop.
import subprocess
p = subprocess.Popen(["python", "--shell", "positional_arg1", "positional_arg2",
"--option", "optional_arg1", "--True_flag"], shell=True,
stdout=subprocess.PIPE)
out, err = p.communicate()
There's a file named startup.cmd that sets some environment variables, runs some preparation commands, then does:
start "startup" cmd /k
Which opens a command shell named startup. The manual process I'm trying to automate is to then enter the following command into this shell: get startup.xml. I thought the correct way to do this in Python would be something like this:
import subprocess
p = subprocess.Popen('startup.cmd', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
getcommand = 'get startup.xml'
servercommand = 'startserver'
p.stdin.write(getcommand)
p.stdin.write(startserver)
(stdoutdata, stderrdata) = p.communicate()
print stdoutdata
print stderrdata
But those commands don't seem to be executing in the shell. What am I missing? Also, the command shell appears regardless of whether shell is set to True or False.
I found this warning in subprocess's document,
Warning Use communicate() rather than .stdin.write, .stdout.read or .stderr.read to avoid deadlocks due to any of the other OS pipe buffers filling up and blocking the child process.
So my suggestion is to use communicate to send your command.
import subprocess
p = subprocess.Popen('startup.cmd', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
command = 'get startup.xml\n'
command += 'startserver\n'
(stdoutdata, stderrdata) = p.communicate(command)
print stdoutdata
print stderrdata
This is a new process, so one cannot communicate directly with Popen.