77

I use "source" inside a bash script, as follows:

#!/bin/bash
source someneatscriptthatendsprematurely.sh

I would like to exit from the someneatscriptthatendsprematurely.sh script, without exiting from the main script.

Any help appreciated!

salvador
  • 107
  • 4
codar
  • 7,018
  • 2
  • 18
  • 8

3 Answers3

116

You need the return statement:

return [n]

Causes a function to exit with the return value specified by n. If n is omitted, the return status is that of the last command executed in the function body. If used outside a function, but during execution of a script by the . (source) command, it causes the shell to stop executing that script and return either n or the exit status of the last command executed within the script as the exit status of the script. If used outside a function and not during execution of a script by ., the return status is false. Any command associated with the RETURN trap is executed before execution resumes after the function or script.

You can see this in action with the following two scripts:

script1.sh:
    . script2.sh
    echo hello again

script2.sh:
    echo hello
    return
    echo goodbye

When you run script1.sh, you see:

hello
hello again
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 5
    Do note that you should `return 0` explicitly by default if you can. Not doing so can cause undesired behaviour in the parent script. i.e. `[ -z "non-existant-file" ] && return` will actually return 1. – Brett Ryan Aug 03 '12 at 08:50
  • 5
    @BrettRyan the problem with your example is that `[ -z "non-existant-file" ] && return 0` will return 1. So telling people to explicitly `return 0` and then showing an example where that doesn't work is confusing. – Segfault Nov 27 '17 at 17:47
  • Brett, that doesn't actually matter in the example I posted since the calling script doesn't actually check the return value in any way (via, for example, `if`, `$?` or `set -e`). In any case, I'm pretty certain the quote I included makes the behaviour clear in that case. – paxdiablo Nov 28 '17 at 01:22
0

Is it important that you can change environment variables? Since otherwise you can just execute the script by executing it without source:

someneatscriptthatendsprematurely.sh
Bart Sas
  • 1,595
  • 11
  • 9
0

I had the same problem just now

I realized that adding a checker function and returning that will not also return the function on its caller for example.

On bash_functions

function install_packer_linux() {
  check_wget && check_unzip
  wget https://releases.hashicorp.com/packer/1.1.2/packer_1.1.2_linux_amd64.zip
  unzip packer_1.1.2_linux_amd64.zip
  mv packer ~/.local/bin
  rm -f packer_1.1.2_linux_amd64.zip
}


function check_unzip() {
  if ! [ -x "$(command -v unzip)" ]; then
    echo "Error: unzip is not installed"
    return 1
  else
    return 0
  fi
}

function check_wget() {
  if ! [ -x "$(command -v wget)" ]; then
    echo "Error!: wget is not installed"
    return 1
  else
    return 0
  fi
}


$ source ~/.bash_functions

What happens here is since the checkers is the only place its returned so install_packer_linux will still continue

So you can do two things here. Either keep the current format (function calling another function) as is and evaluate using truthy value then return if the values are not truthy or rewrite the checker on the main installer_packer_linux function

Truthy:

function install_packer_linux() {
  check_wget && check_unzip || return
  wget https://releases.hashicorp.com/packer/1.1.2/packer_1.1.2_linux_amd64.zip
  unzip packer_1.1.2_linux_amd64.zip
  mv packer ~/.local/bin
  rm -f packer_1.1.2_linux_amd64.zip
}

Notice we added || return after the checks and concatenated the checks using && so if not both checks are truthy we return the function

Kenichi Shibata
  • 148
  • 2
  • 11