Garrett
Garrett

Reputation: 4394

How to stop execution in script which may have been sourced or directly executed

If my script gets sourced with

. ./my_script.sh
source ./my_script.sh

then to stop execution in the script, I would use return.

If my script is directly executed with

./my_script.sh
bash ./my_script.sh

then I'd insert an exit.

If I don't know whether the user will source it or directly execute it, how can I cleanly stop the script without killing the terminal it was called from?

Preferably, the code snippet should be able to terminate the script even if it were placed inside one of the script's functions.

Upvotes: 3

Views: 2999

Answers (2)

R Sahu
R Sahu

Reputation: 206617

Here's one way to find out which method was used to invoke the script.

if [[ "$0" == "bash" ]]; then
   echo "source 'file' was used"
else
   echo "bash 'file' was used"
fi

Update, In response to comment by @mklement0:

If your script is named my_script.sh, you can use

b=$(basename "$0")
if [[ "$b" == "my_script.sh" ]]; then
   echo "bash 'file' was used"
else
   echo "source 'file' was used"
fi

Upvotes: 1

mklement0
mklement0

Reputation: 438153

Try the following:

ec=0 # determine the desired exit code

return $ec 2>/dev/null || exit $ec

return will succeed if the script is being sourced, otherwise exit will kick in. The 2>/dev/null suppresses the error message in case the script is not sourced.

The net effect is that the script will terminate with the desired exit / return code, regardless of whether it was sourced or not.


Update: The OP wants to be able to exit the script from inside a function within the script.

The only way I can think of is to place all of your script's code in a subshell and call exit from inside the functions inside that subshell; then place the return 2>/dev/null || exit command after the subshell (as the only statement outside the subshell):

#!/usr/bin/env bash

( # subshell to place all code in

  foo() {
    exit 1  # exit the subshell
  }

  foo # invoke the function

)

# Terminate script with exit code from subshell.
ec=$?; return $ec 2>/dev/null || exit $ec

Upvotes: 7

Related Questions