Any way to exit bash script, but not quitting the terminal

LinuxBash

Linux Problem Overview


When I use exit command in a shell script, the script will terminate the terminal (the prompt). Is there any way to terminate a script and then staying in the terminal?

My script run.sh is expected to execute by directly being sourced, or sourced from another script.

EDIT: To be more specific, there are two scripts run2.sh as

...
. run.sh
echo "place A"
...

and run.sh as

...
exit
...

when I run it by . run2.sh, and if it hit exit codeline in run.sh, I want it to stop to the terminal and stay there. But using exit, the whole terminal gets closed.

PS: I have tried to use return, but echo codeline will still gets executed....

Linux Solutions


Solution 1 - Linux

The "problem" really is that you're sourcing and not executing the script. When you source a file, its contents will be executed in the current shell, instead of spawning a subshell. So everything, including exit, will affect the current shell.

Instead of using exit, you will want to use return.

Solution 2 - Linux

Yes; you can use return instead of exit. Its main purpose is to return from a shell function, but if you use it within a source-d script, it returns from that script.

As §4.1 "Bourne Shell Builtins" of the Bash Reference Manual puts it:

> return [n] > Cause a shell function to exit with the return value n. If n is not supplied, the return value is the exit status of the last command executed in the function. This may also be used to terminate execution of a script being executed with the . (or source) builtin, returning either n or the exit status of the last command executed within the script as the exit status of the script. Any command associated with the RETURN trap is executed before execution resumes after the function or script. The return status is non-zero if return is used outside a function and not during the execution of a script by . or source.

Solution 3 - Linux

You can add an extra exit command after the return statement/command so that it works for both, executing the script from the command line and sourcing from the terminal.

Example exit code in the script:

   if [ $# -lt 2 ]; then
     echo "Needs at least two arguments"
     return 1 2>/dev/null
     exit 1
   fi

The line with the exit command will not be called when you source the script after the return command.

When you execute the script, return command gives an error. So, we suppress the error message by forwarding it to /dev/null.

Solution 4 - Linux

Instead of running the script using . run2.sh, you can run it using sh run2.sh or bash run2.sh

A new sub-shell will be started, to run the script then, it will be closed at the end of the script leaving the other shell opened.

Solution 5 - Linux

Actually, I think you might be confused by how you should run a script.

If you use sh to run a script, say, sh ./run2.sh, even if the embedded script ends with exit, your terminal window will still remain.

However if you use . or source, your terminal window will exit/close as well when subscript ends.

for more detail, please refer to What is the difference between using sh and source?

Solution 6 - Linux

This is just like you put a run function inside your script run2.sh. You use exit code inside run while source your run2.sh file in the bash tty. If the give the run function its power to exit your script and give the run2.sh its power to exit the terminator. Then of cuz the run function has power to exit your teminator.

    #! /bin/sh
    # use . run2.sh
    
    run()
    {
    	echo "this is run"
    	#return 0
        exit 0
    }

    echo "this is begin"
    run
    echo "this is end"
    

Anyway, I approve with Kaz it's a design problem.

Solution 7 - Linux

I had the same problem and from the answers above and from what I understood what worked for me ultimately was:

  1. Have a shebang line that invokes the intended script, for example,

#!/bin/bash uses bash to execute the script

I have scripts with both kinds of shebang's. Because of this, using sh or . was not reliable, as it lead to a mis-execution (like when the script bails out having run incompletely)

The answer therefore, was

    • Make sure the script has a shebang, so that there is no doubt about its intended handler.

    • chmod the .sh file so that it can be executed. (chmod +x file.sh)

    • Invoke it directly without any sh or .

      (./myscript.sh)

Hope this helps someone with similar question or problem.

Solution 8 - Linux

I think that this happens because you are running it on source mode with the dot

. myscript.sh

You should run that in a subshell:

/full/path/to/script/myscript.sh

'source' http://ss64.com/bash/source.html

Solution 9 - Linux

It's correct that sourced vs. executed scripts use return vs. exit to keep the same session open, as others have noted.

Here's a related tip, if you ever want a script that should keep the session open, regardless of whether or not it's sourced.

The following example can be run directly like foo.sh or sourced like . foo.sh/source foo.sh. Either way it will keep the session open after "exiting". The $@ string is passed so that the function has access to the outer script's arguments.

#!/bin/sh
foo(){
    read -p "Would you like to XYZ? (Y/N): " response;
    [ $response != 'y' ] && return 1;
    echo "XYZ complete (args $@).";
    return 0;
    echo "This line will never execute.";
}
foo "$@";

Terminal result:

> $ foo.sh
> $ Would you like to XYZ? (Y/N): n
> $ . foo.sh
> $ Would you like to XYZ? (Y/N): n
> $ |
> (terminal window stays open and accepts additional input)

This can be useful for quickly testing script changes in a single terminal while keeping a bunch of scrap code underneath the main exit/return while you work. It could also make code more portable in a sense (if you have tons of scripts that may or may not be called in different ways), though it's much less clunky to just use return and exit where appropriate.

Solution 10 - Linux

Also make sure to return with expected return value. Else if you use exit when you will encounter an exit it will exit from your base shell since source does not create another process (instance).

Solution 11 - Linux

To write a script that is secure to be run as either a shell script or sourced as an rc file, the script can check and compare $0 and $BASH_SOURCE and determine if exit can be safely used.

Here is a short code snippet for that

[ "X$(basename $0)" = "X$(basename $BASH_SOURCE)" ] && \
    echo "***** executing $name_src as a shell script *****" || \
    echo "..... sourcing $name_src ....."

Solution 12 - Linux

if your terminal emulator doesn't have -hold you can sanitize a sourced script and hold the terminal with:

#!/bin/sh
sed "s/exit/return/g" script >/tmp/script
. /tmp/script
read

otherwise you can use $TERM -hold -e script

Solution 13 - Linux

Improved the answer of Tzunghsing, with more clear results and error re-direction, for silent usage:

#!/usr/bin/env bash

echo -e "Testing..."

if [ "X$(basename $0 2>/dev/null)" = "X$(basename $BASH_SOURCE)" ]; then
    echo "***** You are Executing $0 in a sub-shell."
    exit 0
else
    echo "..... You are Sourcing $BASH_SOURCE in this terminal shell."
    return 0
fi

echo "This should never be seen!"

Or if you want to put this into a silent function:

function sExit() {
    # Safe Exit from script, not closing shell.
    [ "X$(basename $0 2>/dev/null)" = "X$(basename $BASH_SOURCE)" ] && exit 0 || return 0
}

...

# ..it have to be called with an error check, like this: 
sExit && return 0

echo "This should never be seen!"

Please note that:

  • if you have enabled errexit in your script (set -e) and you return N with N != 0, your entire script will exit instantly. To see all your shell settings, use, set -o.
  • when used in a function, the 1st return 0 is exiting the function, and the 2nd return 0 is exiting the script.

Solution 14 - Linux

If a command succeeded successfully, the return value will be 0. We can check its return value afterwards.

Is there a “goto” statement in bash? > Here is some dirty workaround using trap which jumps only backwards.


#!/bin/bash
set -eu
trap 'echo "E: failed with exitcode $?" 1>&2' ERR

my_function () {
    if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
        echo "this is run"
        return 0
    else
        echo "fatal: not a git repository (or any of the parent directories): .git"
        goto trap 2> /dev/null
    fi
}

my_function
echo "Command succeeded"  # If my_function failed this line is not printed

Related:

Solution 15 - Linux

You just need to end your sh script with the command:

bash

Anything beyond that is part of your creativity. :)

Solution 16 - Linux

I couldn't find solution so for those who want to leave the nested script without leaving terminal window:

# this is just script which goes to directory if path satisfies regex
wpr(){
    leave=false
    pwd=$(pwd)
    if [[ "$pwd" =~ ddev.*web ]]; then
        # echo "your in wordpress instalation"
        wpDir=$(echo "$pwd" | grep -o  '.*\/web')
        cd $wpDir
        return
    fi
    echo 'please be in wordpress directory'
    # to leave from outside the scope
    leave=true
    return
}

wpt(){
    # nested function which returns $leave variable
    wpr
    
    # interupts the script if $leave is true
    if $leave; then
        return;
    fi
    echo 'here is the rest of the script, executes if leave is not defined'
}

Solution 17 - Linux

  1. exit 0 will come out of the script if it is successful.

  2. exit 1 will come out of the script if it is a failure.

You can try these above two based on ur req.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRichardView Question on Stackoverflow
Solution 1 - LinuxDominik HonnefView Answer on Stackoverflow
Solution 2 - LinuxruakhView Answer on Stackoverflow
Solution 3 - LinuxnonameView Answer on Stackoverflow
Solution 4 - LinuxViorel MireaView Answer on Stackoverflow
Solution 5 - Linuxkarl liView Answer on Stackoverflow
Solution 6 - LinuxUmaeView Answer on Stackoverflow
Solution 7 - Linuxgk_2000View Answer on Stackoverflow
Solution 8 - LinuxJBoyView Answer on Stackoverflow
Solution 9 - LinuxBeejorView Answer on Stackoverflow
Solution 10 - Linuxcoder23View Answer on Stackoverflow
Solution 11 - LinuxTzunghsing David WongView Answer on Stackoverflow
Solution 12 - LinuxtechnosaurusView Answer on Stackoverflow
Solution 13 - Linuxnot2qubitView Answer on Stackoverflow
Solution 14 - LinuxalperView Answer on Stackoverflow
Solution 15 - LinuxinTerActionVRIView Answer on Stackoverflow
Solution 16 - LinuxPaweł WitekView Answer on Stackoverflow
Solution 17 - LinuxTejaView Answer on Stackoverflow