Thursday, March 6, 2008

Exporting Shell Variables "Upwards"

A common question is "How can I set a variable in a shell script and then use it after the shell script finishes executing?"

You can't.
$ cat anotherscript
x=3
$ x=69; ./anotherscript; echo $x
69

"Can't I do this with export?" Nope, export only exports downwards in the process tree.

When you want to modularize your shell scripts, by wrapping pieces in little modules, how can you do it?

One way is to write the result to standard out:
$ cat anotherscript
x=3
echo $x
$ x=69; x=$(./anotherscript); echo $x
3
This works, but if you want to pass up more than one variable, it gets awkward.

A second is to source the module.
$ cat anotherscript
x=foo
y=bar
$ source anotherscript
$ echo $x, $y
foo, bar
This runs everything in the same shell, so it exposes everything the module's doing. That's not exactly "modular."

Here's a third approach that lets you "export" variables "upwards." You have to use eval, but it gives you what you want with a reasonable syntax.
$ cat example
source raise.sh # a magic module

raise foo bar # mark variables to be "raised"

foo=hello # do stuff with them in the script
bar=world

$ eval $(example) # now use the script
$ echo $foo, $bar # and see that they're available.
hello, world
$ cat raise.sh
raise() {
trap "4eval $*" EXIT
}

4eval() {
for i in $*
do
echo $i=${!i}
done
}

No comments: