Get exit status of last command in Python script - python

How can I get the exist status (if command succeed or not) of any line in Python?
For example in bash, $? will tell me the last exist status of any command.
I need it to know if my connection to FTP server was successful or not.

Have you tried using a try/catch? If there was an error while executing the command, an exception will be raised. You can retrieve it with the sys module.
Example code:
import sys
try:
run_command()
except:
e = sys.exc_info()[0]
print(e)

If it is a function you call, it should have a retrun code you can collect like
retVal = doSomething()
Then you can check what happened.

Related

How can I get the output of a Timed Out command by subprocess.check_output()?

I'm trying to run some commands using the python library subprocess. Some of my commands might get stuck in loops and block the python script. Therefore I'm using check_output() with a timeout argument to limit the commands in time. When the command takes too much time, the function raise a TimeoutExpired error. What I want to do is get what the command has been able to run before being killed by the timeout.
I've except the error and tried "except sp.TimeoutExpired as e:". I read on the doc that if I do e.output it should give me what I want. "Output of the child process if this exception is raised by check_output(). Otherwise, None.". However I don't get anything in the output.
Here is what I did:
import subprocess as sp
try:
out = sp.check_output('ls', stderr=sp.STDOUT, universal_newlines=True, timeout=1)
except sp.TimeoutExpired as e:
print ('output: '+ e.output)
else:
return out
Let say the folder I'm working with is huge and so 1 second isn't enough to ls all its files. Therefore the TimeoutExpired error will be raised. However, I'd like to store what the script was able to get at least. Does someone have an idea?
Found a solution, posting it here in case someone is interested.
In Python 3, the run method allows to get the output.
Using the parameters as shown in the example, TimeoutExpired returns the output before the timeout in stdout:
import subprocess as sp
for cmd in [['ls'], ['ls', '/does/not/exist'], ['sleep', '5']]:
print('Running', cmd)
try:
out = sp.run(cmd, timeout=3, check=True, stdout=sp.PIPE, stderr=sp.STDOUT)
except sp.CalledProcessError as e:
print(e.stdout.decode() + 'Returned error code ' + str(e.returncode))
except sp.TimeoutExpired as e:
print(e.stdout.decode() + 'Timed out')
else:
print(out.stdout.decode())
Possible output:
Running ['ls']
test.py
Running ['ls', '/does/not/exist']
ls: cannot access '/does/not/exist': No such file or directory
Returned error code 2
Running ['sleep', '5']
Timed out
I hope it helps someone.

Trouble with subprocess.check_output()

I'm having some strange issues using subprocess.check_output(). At first I was just using subprocess.call() and everything was working fine. However when I simply switch out call() for check_output(), I receive a strange error.
Before code (works fine):
def execute(hosts):
''' Using psexec, execute the batch script on the list of hosts '''
successes = []
wd = r'c:\\'
file = r'c:\\script.exe'
for host in hosts:
res = subprocess.call(shlex.split(r'psexec \\\\%s -e -s -d -w %s %s' % (host,wd,file)))
if res.... # Want to check the output here
successes.append(host)
return successes
After code (doesn't work):
def execute(hosts):
''' Using psexec, execute the batch script on the list of hosts '''
successes = []
wd = r'c:\\'
file = r'c:\\script.exe'
for host in hosts:
res = subprocess.check_output(shlex.split(r'psexec \\\\%s -e -s -d -w %s %s' % (host,wd,file)))
if res.... # Want to check the output here
successes.append(host)
return successes
This gives the error:
I couldnt redirect this because the program hangs here and I can't ctrl-c out. Any ideas why this is happening? What's the difference between subprocess.call() and check_output() that could be causing this?
Here is the additional code including the multiprocessing portion:
PROCESSES = 2
host_sublists_execute = [.... list of hosts ... ]
poolE = multiprocessing.Pool(processes=PROCESSES)
success_executions = poolE.map(execute,host_sublists_execute)
success_executions = [entry for sub in success_executions for entry in sub]
poolE.close()
poolE.join()
Thanks!
You are encountering Python Issue 9400.
There is a key distinction you have to understand about subprocess.call() vs subprocess.check_output(). subprocess.call() will execute the command you give it, then provide you with the return code. On the other hand, subprocess.check_output() returns the program's output to you in a string, but it tries to do you a favor and check the program's return code and will raise an exception (subprocess.CalledProcessError) if the program did not execute successfully (returned a non-zero return code).
When you call pool.map() with a multiprocessing pool, it will try to propagate exceptions in the subprocesses back to main and raise an exception there. Apparently there is an issue with how the subprocess.CalledProcessError exception class is defined, so the pickling fails when the multiprocessing library tries to propagate the exception back to main.
The program you're calling is returning a non-zero return code, which makes subprocess.check_output() raise an exception, and pool.map() can't handle it properly, so you get the TypeError that results from the failed attempt to retrieve the exception.
As a side note, the definition of subprocess.CalledProcessError must be really screwed up, because if I open my 2.7.6 terminal, import subprocess, and manuallly raise the error, I still get the TypeError, so I don't think it's merely a pickling problem.

Is there a way to have a python program run an action when it's about to crash?

I have a python script with a loop that crashes every so often with various exceptions, and needs to be restarted. Is there a way to run an action when this happens, so that I can be notified?
You could install an exception hook, by assigning a custom function to the sys.excepthook handler. The function is called whenever there is a unhandled exception (so one that exits the interpreter).
import sys
def myexcepthook(type, value, tb):
import traceback
from email.mime.text import MIMEText
from subprocess import Popen, PIPE
tbtext = ''.join(traceback.format_exception(type, value, tb))
msg = MIMEText("There was a problem with your program:\n\n" + tbtext)
msg["From"] = "me#example.com"
msg["To"] = "you#example.com"
msg["Subject"] = "Program exited with a traceback."
p = Popen(["/usr/sbin/sendmail", "-t"], stdin=PIPE)
p.communicate(msg.as_string())
sys.excepthook = myexcepthook
This exception hook emails you the traceback whenever the program exits, provided you have a working sendmail command on your system.
You can surrond your whole program with a try/except block, which is not very beautiful I find. Another way is to run your python script in a .sh file and execute this:
#!/bin/bash
while true
do
python your_script.py
if $? != 0 then
sendmail "blabla" "see the doc" "for arguments"
fi
done
This will execute the Python script and when it stops, it'll send you a mail and restarted it (since it's an infinite loop). The mail is sent only if there's an error in the Python program and the exit code is different of 0. To be more efficient, you could get the stdout, and put it in the mail to know what fails and how resolve this.
You should try like this:
while True:
try:
x = int(raw_input("Please enter a number: "))
break
except ValueError:
print "Oops! That was no valid number. Try again..."

sh to py conversion

I'm currently converting a shell script to python and I'm having a problem. The current script uses the results of the last ran command like so.
if [ $? -eq 0 ];
then
testPassed=$TRUE
else
testPassed=$FALSE
fi
I have the if statement converted over just not sure about the $? part. As I am new to python I'm wondering if there is a similar way to do this?
You should look into the subprocess module for that. There is a check_call method for looking into exit codes (this is one method, there are others as well). As the manual mentions:
Run command with arguments. Wait for command to complete. If the
return code was zero then return, otherwise raise CalledProcessError.
The CalledProcessError object will have the return code in the
returncode attribute
An example of this is:
import subprocess
command=["ls", "-l"]
try:
exit_code=subprocess.check_call(command)
# Do something for successful execution here
print("Program run")
except subprocess.CalledProcessError as e:
print "Program exited with exit code", e.returncode
# Do something for error here
This will also include output, which you can either redirect to a file or suppress like so:
import subprocess
import os
command=["ls", "-l"]
try:
exit_code=subprocess.check_call(command, stdout=open(os.devnull, "w"))
# Do something for successful execution here
print("Program run")
except subprocess.CalledProcessError as e:
print "Program exited with exit code", e.returncode
# Do something for error here
Here is an example of a call with a non-zero exit code:
import subprocess
import os
command=["grep", "mystring", "/home/cwgem/testdir/test.txt"]
try:
exit_code=subprocess.check_call(command, stdout=open(os.devnull, "w"))
# Do something for successful execution here
print("Program run")
except subprocess.CalledProcessError as e:
print "Program exited with exit code", e.returncode
# Do something for error here
Output:
$ python process_exitcode_test.py
Program exited with exit code 1
Which is captured as an exception that you can handle as above. Note that this will not handle exceptions such as access denied or file not found. You will need to handle them on your own.
You might want use the sh module. It makes shell scripting in Python much more pleasant:
import sh
try:
output = sh.ls('/some/nen-existant/folder')
testPassed = True
except ErrorReturnCode:
testPassed = False

exit failed script run (python)

I have seen several questions about exiting a script after a task is successfully completed, but is there a way to do the same for a script which has failed? I am writing a testing script which just checks that a camera is functioning correctly. If the first test fails it is more than likely that the following tests will also fail; therefore, I want the first failure to invoke an exit and provide output to screen letting me know that there was an error.
I hope this is enough information; let me know if more details are required to help me.
Are you just looking for the exit() function?
import sys
if 1 < 0:
print >> sys.stderr, "Something is seriously wrong."
sys.exit(1)
The (optional) parameter of exit() is the return code the script will return to the shell. Usually values different than 0 signal an error.
You can use sys.exit() to exit. However, if any code higher up catches the SystemExit exception, it won't exit.
You can raise exceptions to identify error conditions. Your top-level code can catch those exceptions and handle them appropriately. You can use sys.exit to exit. E.g., in Python 2.x:
import sys
class CameraInitializationError(StandardError):
pass
def camera_test_1():
pass
def camera_test_2():
raise CameraInitializationError('Failed to initialize camera')
if __name__ == '__main__':
try:
camera_test_1()
camera_test_2()
print 'Camera successfully initialized'
except CameraInitializationError, e:
print >>sys.stderr, 'ERROR: %s' % e
sys.exit(1)
You want to check the return code from the c++ program you are running, and exit if it indicates failure. In the code below, /bin/false and /bin/true are programs that exit with error and success codes, respectively. Replace them with your own program.
import os
import sys
status = os.system('/bin/true')
if status != 0:
# Failure occurred, exit.
print 'true returned error'
sys.exit(1)
status = os.system('/bin/false')
if status != 0:
# Failure occurred, exit.
print 'false returned error'
sys.exit(1)
This assumes that the program you're running exits with zero on success, nonzero on failure.

Categories

Resources