1

I have a script that I'd like people to source, but optionally so. So they can run it with or without sourcing it, it's up to them.

e.g. The following should both work:

$ . test.sh $ test.sh

The problem is, test.sh contains exit statements if correct args aren't passed in. If someone sources the script, then the exit commands exit the terminal!

I've done a bit of research and see from this StackOverflow post that I could detect if it's being sourced, and do something different, but what would that something different be?

Brad Parks
  • 66,836
  • 64
  • 257
  • 336

3 Answers3

2

The normal way to exit from a sourced script is simply to return (optionally adding the desired exit code) outside of any function. Assuming that when run as a command we have the -e flag set, this will also exit from a shell program:

#!/bin/sh -eu

if [ $# = 0 ]
then
    echo "Usage $0 <argument>" >&2 
    return 1
fi

If we're running without -e, we might be able to return || exit instead.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • Thanks for the feedback - yeah I want it to work source and not sourced - can you show an example of this working both ways? – Brad Parks Oct 04 '19 at 15:24
  • I tried it and it works as you give for an example - but I guess the use case for me is I like to have functions that can `exit` at anytime - and this approach doesnt seem to let that happen? – Brad Parks Oct 04 '19 at 16:51
1

There may be better ways to do this, but here's a sample script showing how I got this to work:

bparks@home 
$ set | grep TESTVAR

bparks@home 
$ ./test.sh

  Outputs some useful information to the console. Please pass one arg.

bparks@home 
$ set | grep TESTVAR

bparks@home 
$ . ./test.sh

  Outputs some useful information to the console. Please pass one arg.

bparks@home 
$ set | grep TESTVAR

bparks@home 
$ ./test.sh asdf
export TESTVAR=me

bparks@home 
$ set | grep TESTVAR

bparks@home 
$ . ./test.sh asdf

bparks@home 
$ set | grep TESTVAR
TESTVAR=me

bparks@home 
$

test.sh

#!/usr/bin/env bash

# store if we're sourced or not in a variable
(return 0 2>/dev/null) && SOURCED=1 || SOURCED=0

exitIfNotSourced(){
  [[ "$SOURCED" != "0" ]] || exit;
}

showHelp(){
  IT=$(cat <<EOF

  Outputs some useful information to the console. Please pass one arg.

EOF
  )
  echo "$IT"
}

# Show help if no args supplied - works if sourced or not sourced
if [ -z "$1" ]
then
  showHelp

  exitIfNotSourced;
  return;
fi

# your main script follows 
# this sample shows exporting a variable if sourced, 
# and outputting this to stdout if not sourced

if [ "$SOURCED" == "1" ]
then
  export TESTVAR=me
else
  echo "export TESTVAR=me"
fi
Brad Parks
  • 66,836
  • 64
  • 257
  • 336
0

Checkout this answer for better description and porper solution.

And here is how it is used in docker-entrypoint.sh in official Mysql image:

# check to see if this file is being run or sourced from another script
_is_sourced() {
    # https://unix.stackexchange.com/a/215279
    [ "${#FUNCNAME[@]}" -ge 2 ] \
        && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
        && [ "${FUNCNAME[1]}" = 'source' ]
}
Arkemlar
  • 380
  • 4
  • 12