LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 10-14-2008, 05:30 AM   #1
SwingingSimian
LQ Newbie
 
Registered: Aug 2008
Posts: 10

Rep: Reputation: 0
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.

Any suggestions would be greatly appreciated.

Thanks

Nath
 
Old 10-14-2008, 07:21 AM   #2
mudflap
Member
 
Registered: Jul 2008
Location: Coffin Point
Distribution: Slackware - ttylinux - CPO
Posts: 53

Rep: Reputation: 15
>> SwingingSimian

I am not sure if I understand what you are doing, but I will jump in anyway.

Will multiple terminals solve your problem? Each terminal should maintain an independant environment.

It sounds like a "chroot" might be a better approach.
 
Old 10-14-2008, 10:41 AM   #3
SwingingSimian
LQ Newbie
 
Registered: Aug 2008
Posts: 10

Original Poster
Rep: Reputation: 0
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.
 
Old 10-15-2008, 07:17 AM   #4
mudflap
Member
 
Registered: Jul 2008
Location: Coffin Point
Distribution: Slackware - ttylinux - CPO
Posts: 53

Rep: Reputation: 15
>> SwingingSimian


How about:

---
ding_bell() {
echo -e "\a"
}

alias exit="ding_bell"
---

"unalias exit" will restore exit to expected behaviour, no need then to invoke another instance of bash. The environment remains unique to that terminal.
 
Old 10-15-2008, 07:10 PM   #5
chrism01
Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 6.5, Centos 5.10
Posts: 16,289

Rep: Reputation: 2034Reputation: 2034Reputation: 2034Reputation: 2034Reputation: 2034Reputation: 2034Reputation: 2034Reputation: 2034Reputation: 2034Reputation: 2034Reputation: 2034
Here's another way of changing what exit does: http://www.tldp.org/LDP/abs/html/functions.html
Look at the NO_EXIT example.
Or you can use the 'return' cmd from within a fn: http://www.faqs.org/docs/abs/HTML/functions.html
 
Old 10-16-2008, 04:47 AM   #6
SwingingSimian
LQ Newbie
 
Registered: Aug 2008
Posts: 10

Original Poster
Rep: Reputation: 0
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.

Nath
 
Old 10-16-2008, 05:09 AM   #7
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
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).
 
Old 10-16-2008, 05:15 AM   #8
SwingingSimian
LQ Newbie
 
Registered: Aug 2008
Posts: 10

Original Poster
Rep: Reputation: 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.

Thanks

Nath
 
Old 08-11-2009, 03:12 PM   #9
kdogksu
Member
 
Registered: Dec 2004
Location: Kansas, United States
Distribution: Ubuntu
Posts: 52

Rep: Reputation: 16
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
}
 
Old 08-12-2009, 12:50 AM   #10
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,551
Blog Entries: 28

Rep: Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176
Quote:
Originally Posted by SwingingSimian View Post
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.
 
Old 08-12-2009, 12:59 AM   #11
RaptorX
Member
 
Registered: Jun 2009
Location: Emden, Germany
Distribution: Slackware 12.2, Slax 6.1
Posts: 254

Rep: Reputation: 37
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>.
So you can give it a try to see what happens.

snipped from Advanced Bash Scripting tutorial.
http://tldp.org/LDP/abs/html/here-docs.html#HEREDOCREF

Last edited by RaptorX; 08-12-2009 at 03:05 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Why is DC++ exiting after a while? Kristoffer G Mandriva 24 09-26-2007 01:34 PM
10.0 and Nvidia drivers=white char in bash after exiting KDE please help DDR extreme Mandriva 0 07-20-2004 10:53 PM
gxine exiting itself XPediTioN Slackware 1 07-14-2004 11:24 AM
Exiting X KarmaKill Fedora 1 06-24-2004 02:46 PM
Exiting X AstrumPreliator Linux - Newbie 1 09-08-2003 07:37 PM


All times are GMT -5. The time now is 04:35 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration