Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Python: how can I get the exit status of the previous process run from Bash (i.e. "$?")?

I have a Python script that should report success or failure of the previous command. Currently, I'm doing

command && myscript "Success" || myscript "Failed"

What I would like to do is instead to be able to run the commands unlinked as in:

command; myscript

And have myscript retrieve $?, i.e. the exist status. I know I could run:

command; myscript $?

But what I'm really looking for is a Python way to retrieve $? from Python.

How can I do it?


Since this is a strange request, let me clarify where it comes from. I have a Python script that uses the pushover API to send a notification to my phone.

When I run a long process, I run it as process && notify "success" || notify "failure". But sometimes I forget to do this and just run the process. At this point, I'd like to run "notify" on the still processing command line, and have it pick up the exit status and notify me.

Of course I could also implement the pushover API call in bash, but now it's become a question of figuring out how to do it in Python.

like image 564
Miquel Avatar asked Oct 29 '14 09:10

Miquel


3 Answers

This may not be possible, because of how a script (of any language, not just Python) gets executed. Try this: create a shell script called retcode.sh with the following contents:

#!/bin/bash
echo $?

Make it executable, then try the following at a shell prompt:

foo # Or any other non-existent command
echo $?  # prints 127
foo
./retcode.sh  # prints 0

I'd have to double-check this, but it seems that all scripts, not just Python scripts, are run in a separate process that doesn't have access to the exit code of the previous command run by the "parent" shell process. Which may explain why Python doesn't (as far as I can tell) give you a way to retrieve the exit code of the previous command like bash's $? — because it would always be 0, no matter what.

I believe your approach of doing command; myscript $? is the best way to achieve what you're trying to do: let the Python script know about the exit code of the previous step.

Update: After seeing your clarification of what you're trying to do, I think your best bet will be to modify your notify script just a little, so that it can take an option like -s or --status (using argparse to make parsing options easier, of course) and send a message based on the status code ("success" if the code was 0, "failure NN" if it was anything else, where NN is the actual code). Then when you type command without your little && notify "success" || notify "failure" trick, while it's still running you can type notify -s $? and get the notification you're looking for, since that will be the next thing that your shell runs after command returns.

like image 197
rmunn Avatar answered Oct 05 '22 17:10

rmunn


false; export ret=$?; ./myscript2.py

myscript2.py:

#!/usr/bin/python

import os
print os.environ['ret']

Output:

1
like image 42
Cyrus Avatar answered Oct 05 '22 19:10

Cyrus


It is clearly not possible: the exit value of a process is only accessible to its parent, and no shells I know offer an API to allow next process to retrieve it.

IMHO, what is closer to your need would be:

process
myscript $?

That way, you can do it even if you started you process without thinking about notification.

You could also make the script able to run a process get the exit code and to its notification, or (depending on options given in command line) use an exit code given as parameter. For example, you could have:

  • myscript process: runs process and does notifications
  • myscript -c $?: only does notifications

argparse module can make that easy.

like image 44
Serge Ballesta Avatar answered Oct 05 '22 19:10

Serge Ballesta