Exiting BASH function without exiting sourced environment
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Exiting BASH function without exiting sourced environment
Hi all
I'm writing an environment in BASH and want to be able to exit from a function without exiting from the whole environment.
For example:
>. my_env.sh
#This sets PS1 to my_env and contains a function called RunExit, which simply exits. The idea is that this will be called by other functions when an error is encountered, but we simply want to stop running the function, rather than exiting the environment
This is what happens with a simple exit command
my_env>RunExit
>
Where as I want to be able just to exit the function, so that we still have access to the environment and all of it's config & functions e.g.
my_env>RunExit
my_env>
I'm currently trapping all EXIT commands with a function which simply calls bash just before it ends, so it exits from the subshell rather than from the environment.
################################################################################
# Func : ReportExit()
# Desc : Reports exit status but calls bash before exit, so we don't exit the environment
# Args [1] :
# Return :
# Exception :
################################################################################
ReportExit(){
es=$?
echo "Exiting with status:$es"
bash
}
This seems to work okay. But this doesn't work all the time and I end up with several instances of bash running. I guess there is a cleaner way of doing this, but I can't find anything obvious at the moment.
No I don't think so, I want all this running via one terminal.
The enviroment is supposed to set up some config when sourced and then return you to the command line where you can execute any number of interactive functions which were defined in the environment.
What I want is a way to exit from a function without exiting the environment. Return doesn't work as this simply returns to the caller function, which would mean I would have to do some sort of mammoth return value tracking right back to the function originally called.
"unalias exit" will restore exit to expected behaviour, no need then to invoke another instance of bash. The environment remains unique to that terminal.
Thanks guys, but aliasing exit simply returns me to the caller of exit after the aliased function has finished, hence the rest of the caller is executed and not really exited. Obviously return does the same
, which is what I want to avoid.
I actually want the script to stop running from any point in a series of potentially nested functions, but without exiting the environment which was sourced.
e.g.
The methods are sourced on the command line from an environment file
Func1(){
Func2
Func3
}
Func2(){
exit
}
Aliasing or returning would from Func2 simply returns to Func1 and Func3 would be executed, which is what I want to avoid. Normal exit behaviour exits the environment totally an none of the above Funcs or associated environment are available.
You'll have to test the return values of your functions to determine if you want to continue execution, or return up the stack to unwind (this is like setjump/longjmp).
Ah, this is what I feared, so I will have to implement return value tracking through all of my functions. I'll take a look setjump/longjmp to see whether they have any neat solutions.
Sorry for a late response, but this may be helpful to others.
I'm a little confused also about what you're trying to do. The first post sounds like you want "exit" in a function to only return from the function and not exit the environment, and in the last post, it sounds like you wanted it to exit completely so that you didn't have to trace the return values.
Regardless, you may want to look into the "set -e" option of Bash. This will exit a script when any shell command returns a non-zero status. If you want your function to exit the entire script without having to track return values, you can "set -e" in the caller, then "return 1" from the function to exit the whole script/environment. ("return 0" continues execution normally.) If you only want this for certain areas of your script, you can later call "set +e" to disable this option.
In one of my scripts, I wanted a function to collect the output of shell commands, but not print it unless there was an error. This keeps the user from seeing all the messy output of verbose commands, but allows it to be displayed if something goes wrong. I had trouble because "set -e" was set in my environment to quit if the function returned "1", but this caused the shell to exit after the failed shell command itself, not waiting until the wrapper function exited. I fixed this by querying the status of "-e", disabling it in the function, then restoring it after running the command but before returning from the function. This function is included below as an example. (I'm not a great shell scripter, so neither quality nor efficiency is guaranteed. )
Ultimately, it would be nice if "exit" exited a whole environment, while "return" only exited a function as it is in C. However, this doesn't seem to be the case.
Code:
# Runs a command, collecting output in a file. The output is
# only displayed if the command returns a non-zero status.
run_clean() {
local output_file="$(mktemp /tmp/output-XXXXXX)"
local die="no"
local autoexit="off"
# Query status of "-e", disable if set
if echo ${-} | grep "e" > /dev/null; then
autoexit="on"
set +e
fi
# Run command and display output if return value is non-zero
${*} > ${output_file} 2>&1
if [ ${?} -ne 0 ]; then
cat ${output_file}
die="yes"
fi
# Restore "-e"
if [ "${autoexit}" == "on" ]; then
set -e
fi
# Cleanup
rm ${output_file}
if [ "${die}" == "yes" ]; then
exit 1;
fi
return 0
}
Ah, this is what I feared, so I will have to implement return value tracking through all of my functions. I'll take a look setjump/longjmp to see whether they have any neat solutions.
setjump/longjmp are C facilities, not bash facilities. I don't think the solution you are looking for exists. What do you want to achieve? There may be another way.
At first I also thought of "return" but as kdogksu mentioned it does not work as in c.
I am not a bash programmer (just a beginner) but I believe that if you "^C" a function it will stop just the function itself, now I do not know if you can pass that in to a script.
EDIT:
according to this script you can:
Quote:
TARGETFILE=$1
# Insert 2 lines in file, then save.
#--------Begin here document-----------#
vi $TARGETFILE <<x23LimitStringx23
i
This is line 1 of the example file.
This is line 2 of the example file.
^[
ZZ
x23LimitStringx23
#----------End here document-----------#
# Note that ^[ above is a literal escape
#+ typed by Control-V <Esc>.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.