views:

173

answers:

4

Hi,

I have a function which I use in my shell script and based on a certain condition I'd like to call "exit 0" in that function so that the entire script exits. But for some reason the program still runs after calling exit 0 in the function. Why?

check()
{
 printf "Would you like to try again?\n"
    read S
 if [ "$S" = "y" ]
 then 
  ./myprog
 else 
  exit 0 
 fi
}

And I call it like this:

if test $WRONG -eq 7
then
    printf "Sorry\n"
    check
fi
A: 

Without any code to go by, I'd guess that your function is invoking a sub-shell, and it's that sub-shell which is exit()ing, and not the parent shell running the main script.

Marc B
I posted my code
goe
Right, it looks like this is what is happening. How can I then exit the main script as well?
goe
I don't see anything that would create a subshell.
DigitalRoss
what about the call to "./myprog" because that when this doesn't work. It does work always the first time the program runs but it doesn't any other.
goe
A: 

I was expecting to find your code exiting a subshell, but I don't see any reason for that, the code looks OK, and it seems to run as expected for me.

So my guess is that either you are not reading a y when you think you are not, or you are really doing the exit 0 and have just missed noticing it in your test results.

When you say "the program still runs" do you mean "the shell program still runs after calling the check procedure"?

DigitalRoss
+2  A: 

What you have works for me:

$ cat test-shell-exit
#!/bin/sh
check()
{
    printf "Would you like to try again?\n"
    read S
    if [ "$S" = "y" ]
    then
        echo Try again
    else
        echo Done
        exit 0
    fi
}
echo Before
check
echo After

$ ./test-shell-exit 
Before
Would you like to try again?
y
Try again
After

$ ./test-shell-exit 
Before
Would you like to try again?
n
Done

Could you try this test case and update your answer with any differences from it? It appears the problem you're running into is caused by something you haven't mentioned.


Update: Example of using a loop instead of calling your program again:

$ cat test-shell-exit 
#!/bin/sh
check()
{
    printf "Would you like to try again?\n"
    read S
    if [ "$S" = "y" ]
    then
        echo Try again
    else
        echo Done
        exit 0
    fi
}
while true; do
    echo Before
    check
    echo After
done

$ ./test-shell-exit 
Before
Would you like to try again?
y
Try again
After
Before
Would you like to try again?
y
Try again
After
Before
Would you like to try again?
n
Done
Roger Pate
Your script worked fine. However I notice something else. One the initial run of my main script this works as well. However if during the first run I choose "y" for the question and my program calls itself again by calling "./myprog" and I get to that question the in that run then the exit fails.
goe
Ah, you're calling the same program again, which means you do invoke a sub-shell, and exiting from that doesn't affect the "outer" shell. Don't do that. Write your program as a loop, with the check determining whether to continue or exit that loop. You could also use `exec` as a limited form of tail recursion, but I'm not sure if that would have unwanted side-effects. (Probably depends on your program.)
Roger Pate
@roger, +1 for `exec`
glenn jackman
So there's no way to force exit from any level of sub-shell?
goe
You can't force a parent process to exit. You can either ask it to exit (with some form of communication) or ask the OS to terminate it (the KILL signal, and this is different from the parent exiting---you definitely don't want this here, either). However, it appears that this problem is better answered with a simple loop instead of either.
Roger Pate
huh, I fixed it by putting "break" after the call to "./myprog", thanks for the help!
goe
A: 

Hi goe

I agree with digitalross that something outside of what you're showing us is causing this behavior. exit 0 WILL exit the current process. so somehow check() is running in a separate child process that is exiting. Do you have code outside of this call that is invoking?

BTW, which OS and shell are you running?

You can force a parent to exit via something like (syntax depends on your shell)

check() || exit $?

Bill

Beel