5

I have a shell script calling Python inside it.

#! /bin/bash

shopt -s extglob
echo "====test===="
~/.conda/envs/my_env/bin/python <<'EOF'

import sys
import os


try:
    print("inside python")
    x = 2/0
except Exception as e:
    print("Exception: %s" % e)
    sys.exit(2)
print("at the end of python")
EOF
echo "end of script"

If I execute this, the lines below still get printed.

"end of script"

I want to exit the shell in the exception block of the python script and let the script not reach EOF

Is there a way to create and kill a subprocess in the except block above, that will kill the entire shell script?

Can I spawn a dummy subprocess and kill it inside the exception block there by killing the entire shell script?

Any examples would be helpful. Thanks in advance.

godimedia
  • 987
  • 2
  • 12
  • 28

3 Answers3

3

From the shell script you have 2 options:

  • set -e: all errors quit the script
  • check python subcommand return code, abort if non-zero

(maybe more details here: Aborting a shell script if any command returns a non-zero value?)

Now, if you don't want to change the handling from your shell script, you could get the parent process of the python script and kill it:

except Exception as e:
    import os,signal,sys
    print("Exception: %s" % e)
    os.kill(os.getppid(),signal.SIGTERM)
    sys.exit(2)

if you need this on windows, this doesn't work (os.kill doesn't exist), you have to adapt it to invoke taskkill:

subprocess.call(["taskkill","/F","/PID",str(os.getppid())])

Now I would say that killing the parent process is bad practice. Unless you don't control the code of this parent process, you should try to handle the exit gracefully.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • 1
    Thanks! Doesn't `os.kill` take 2 parameters, other one being sig? – godimedia Jul 24 '18 at 14:27
  • Thanks, this is what I exactly wanted. Much cleaner and nicer. Works like a charm. – godimedia Jul 24 '18 at 14:49
  • 1
    I would not call that cleaner, but if you have 300 shell scripts, you probably don't want to modify them all, so this is the solution to change only in the python script. This only works if called _directly_ by the shell BTW. – Jean-François Fabre Jul 24 '18 at 14:51
3

The whole EOF ... EOF block gets executed within the Python runtime so exiting from it doesn't affect the bash script. You'll need to collect the exit status and check it after the Python execution if you want to stop the further bash script progress, i.e.:

#!/bin/bash

~/.conda/envs/my_env/bin/python <<'EOF'
import sys

sys.exit(0x01)  # use any exit code from 0-0xFF range, comment out for a clean exit

print("End of the Python script that will not execute without commenting out the above.")
EOF

exit_status=$?  # store the exit status for later use

# now lets check the exit status and see if python returned a non-zero exit status
if [ $exit_status -ne 0 ]; then
    echo "Python exited with a non-zero exit status, abort!"
    exit $exit_status  # exit the bash script with the same status
fi
# continue as usual...
echo "All is good, end of script"
zwer
  • 24,943
  • 3
  • 48
  • 66
0

One way to kill the entire script could be to save the PID and then using Python's system commands to execute a kill command on the PID when the exception happens. If we imported 'os' it would be something along the lines of:

# In a shell
PID=$$
...
// Some Python Exception happens
os.system('kill -9' + $PID)
Robert Brisita
  • 5,461
  • 3
  • 36
  • 35