Search code examples
pythonbashexitstatus

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.


Solution

  • 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.