Reputation: 6355
Consider these 2 scripts:
envSetter.sh:
#!/bin/bash
export ENV_VAR=6
return 3
sourceable.sh:
#!/bin/bash
function main()
{
local var=5
source envSetter.sh
}
main "$@"
unset -f main
envSetter.sh
is a script that sets some variables (and possibly performs other actions that affect the current shell (environment)). I need to create a sourceable script that will source envSetter.sh
but will also clean up after itself. I.e. after running source sourceable.sh
I want my shell to have ENV_VAR
set but I don't want to have main
(or anything else that sourceable.sh
uses) defined.
The above scripts achieve that. However, on top of all that I want sourceable.sh
to be able to return whatever exit code main
returns. Right now the script returns the result of unset -f main
. If I remove that command my script will leave main
function defined which I don't want. If I try to use a temporary variable:
main "$@"
result=$?
unset -f main
return $result
It will return what I expect but will also leave result
defined which I don't want. I could also not use a main
function at all and put all the code in the top level of the script but that would expose even more garbage from inside main
(e.g. local var
) which I also don't want.
Is there a way to source envSetter.sh
(i.e. let it set variables in the current shell), return whatever main
returns and not "pollute" my current shell with anything sourceable.sh
uses? To clarify: I want envSetter.sh
to affect my current shell but I don't want sourceable.sh
to.
Upvotes: 3
Views: 230
Reputation: 141225
You can source the script in a subshell and output relevant stuff you want in a source-able form to stdout. Like so:
tmp=$(
var=5
# silence stdout so that it does not affect what we want
source envSetter.sh >&2
# modify the environment if you want to
unexport ENV_VAR
env_var="$ENV_VAR" # for example rename
# output the environment in a format you want
declare -p env_var ENV_VAR
# declare -f function1 function2 # for functions
# or printf "%q" "$ENV_VAR"
# or write it to a file printf "%s" "$ENV_VAR" > somefile
# ie. save the state where you want to
)
ret=$?
# Load hand picked variables.
eval "$tmp"
echo "ENV_VAR=$ENV_VAR ret=$ret"
Upvotes: 0
Reputation: 125858
How about hiding the unset
command inside of the main
function? Like this:
#!/bin/bash
main() {
unset -f main
local var=5
source envSetter.sh
}
main "$@"
Note that the return status will just propagate through, since source envSetter.sh
is the last command in main
, it'll become the return status of main
, and similarly since main
is the last command in the script, it'll become the return status of the script.
BTW, using a shebang on something that's meant to be run with source
doesn't make much sense. I tend to use something like this:
#!/bin/echo Run this script with the source or . command.
Upvotes: 6
Reputation: 212298
Do your cleanup in a RETURN trap:
#!/bin/bash
trap 'unset -f main' RETURN
main()
{
local var=5
source envSetter.sh
}
main "$@"
Upvotes: 0