I know there are several SO questions on exit
vs. return
in bash
scripts (e.g. here).
On this topic, but different from existing questions, I believe, I'd like to know if there is a "best practice" for how to safely implement "early return" from a bash
script such that the user's current shell is not exited if they source the script.
Answers such as this seem based on "exit
", but if the script is sourced, i.e. run with a ".
" (dot space) prefix, the script runs in the current shell's context, in which case exit
statements have the effect of exiting the current shell. I assume this is an undesirable result because a script doesn't know if it is being sourced or being run in a subshell - if the former, the user may unexpectedly have his shell disappear. Is there a way/best practice for early-returns to not exit the current shell if the caller sources it?
E.g. This script...
#! /usr/bin/bash
# f.sh
func()
{
return 42
}
func
retVal=$?
if [ "${retVal}" -ne 0 ]; then
exit "${retVal}"
# return ${retVal} # Can't do this; I get a "./f.sh: line 13: return: can only `return' from a function or sourced script"
fi
echo "don't wanna reach here"
...runs without killing my current shell if it is run from a subshell...
> ./f.sh
>
...but kills my current shell if it is sourced:
> . ./f.sh
One idea that comes to mind is to nest code within coditionals so that there is no explicit exit
statement, but my C
/C++
bias makes think of early-returns as aesthetically preferable to nested code. Are there other solutions that are truly "early return"?
To add a conditional statement and exit a for loop early, use a break statement. The following code shows an example of using a break within a for loop: #!/bin/bash for i in {1.. 10} do if [[ $i == '2' ]] then echo "Number $i!" break fi echo "$i" done echo "Done!"
To exit from bash type exit and press ENTER . If your shell prompt is > you may have typed ' or " , to specify a string, as part of a shell command but have not typed another ' or " to close the string. To interrupt the current command press CTRL-C .
Often when writing Bash scripts, you will need to terminate the script when a certain condition is met or to take action based on the exit code of a command.
To end a shell script and set its exit status, use the exit command. Give exit the exit status that your script should have. If it has no explicit status, it will exit with the status of the last command run.
Success is traditionally represented with exit 0 ; failure is normally indicated with a non-zero exit-code. This value can indicate different reasons for failure. For example, GNU grep returns 0 on success, 1 if no matches were found, and 2 for other errors (syntax errors, non-existent input files, etc).
The most common solution to bail out of a script without causing the parent shell to terminate is to try return
first. If it fails then exit
.
Your code will look like this:
#! /usr/bin/bash
# f.sh
func()
{
return 42
}
func
retVal=$?
if [ "${retVal}" -ne 0 ]; then
return ${retVal} 2>/dev/null # this will attempt to return
exit "${retVal}" # this will get executed if the above failed.
fi
echo "don't wanna reach here"
You can also use return ${retVal} 2>/dev/null || exit "${retVal}"
.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With