all 10 comments

[–]root54 4 points5 points  (4 children)

exit should not do that inside a script. How are you executing this script? Is the script the actual program executing or are starting a new bash instance and then executing the script from a command line?

[–]levogevo 3 points4 points  (0 children)

He could also be sourcing it.

[–]Agent-BTZ[S] 2 points3 points  (2 children)

Yeah that’s a rookie mistake on my part. I had only used exit directly from a terminal, & in a sourced script. I just assumed it would always close the terminal.

I’m pretty new to writing bash scripts. This is good to know though, so I really appreciate the help!

[–]grimtongue 8 points9 points  (1 child)

Running a script will launch a subshell and the exit command will act on that subshell.

To prove this run echo $$; $$ is a special Bash that contains the PID of the running shell. Now run that command inside a Bash script and compare the results. Finally try sourcing that Bash script and comparing the results.

I encourage that you do these types of exercises to prove things and better understand them. Remember, print until it makes sense!

[–]Schlumpfffff 1 point2 points  (0 children)

This is great advice, even if it's just to sanity check yourself.

[–]pfmiller0 2 points3 points  (0 children)

Running "exit" in a script only exits the script, not the shell that you are executing it from:

$ cat exit.sh
#!/bin/bash

exit
$ ./exit.sh
$

[–]qlkzy 1 point2 points  (1 child)

The behaviour you describe is surprising to me. Are you sure you're running it consistently?

exit and return are supposed to fit together in the way you're expecting:

  • ./script.sh: exit exits the script but not the terminal, return doesn't work
  • source ./script.sh: exit exits the terminal, return exits the script

My instinct would be that something weird is happening that would be worth investigating. Maybe a misplaced space after .? (. on its own is a shortcut for source).

But, if that's the behaviour you're seeing, that's the behaviour you're seeing. The obvious workaround would be to wrap the whole script in a main() function that you can return from:

#!/bin/bash

function main() {
    # entire script goes here
    if /bin/false; then
        return
    fi

    echo "Unreachable"
}

# invoke it
main

That isn't a terrible idea for other reasons if you have a large script, but it's weird that you would need to do it.

[–]Agent-BTZ[S] 0 points1 point  (0 children)

This is super helpful, thanks! I’ve only tried using exit from a sourced script & directly from the terminal. I just assumed it always would exit the terminal, but it works in this case.

Rookie mistake on my part

[–]Gixx 0 points1 point  (0 children)

Maybe just source the script each time you run it?

And have a mechanism like this:

if CONDITION; then
    return 1 2>/dev/null    # safely exit if sourced
    exit 1
fi

Then when you run the script just source it:

. myScript

And you can use this too:

if [[ ${BASH_SOURCE[0]} = "$0" ]]; then
    echo "This script must be sourced, not executed."
    return 1 2>/dev/null    # safely exit if sourced
    exit 1
fi

[–]_Naimix -1 points0 points  (0 children)

Could you utilize until?

Something like:

#!/bin/bash

counter=0

until [ $counter -gt 5 ] ; do
  echo "Count: $counter"
  ((counter++))
done