If you don’t know, environmental variables are used to override options for scripts, apps, and other things you run on computers. In bash they normally look like, something like this:

DEPLOY=production ./release-app.sh

In this contrived example, the DEPLOY option is set to production and any options that are required in ./release-app.sh would do make those changes.

Now, I was experimenting with some scripts lately, and discovered something I hadn’t expected. Lets walk through an example that will hopefully explain it all.

Example

Ok, lets say we have this following script:

FOO="in the script"
echo "This was outputted from" ${FOO}

It outputs:

$ bash script.sh
This was outputted from in the script

Perfect, now lets override this:

$ FOO="from the shell" bash script.sh
This was outputted from the script

What! This wasn’t what expected. I wanted This was outputted from the shell. Ok, lets try something different:

$ export FOO="from the shell"
$ bash script.sh
This was outputted from the script

Damn, this didn’t work either. Looks like we need to edit the script a bit, I removed the FOO line and changed:

echo "This is outputted ${FOO:-"from the script"}

This gives the FOO variable the default of from the script if it’s not declared:

$ bash script.sh
This was outputted from from the script
$ FOO="from the shell" bash script.sh
This was outputted from from the shell
$ export FOO="from the shell"
$ bash run.sh
This was outputted from from the shell

OK this seems more reasonable, now I can change the variables around if I want to.

One last experiment, and hopefully this should make it make total sense on the scoping of environmental varibles in bash.

Let’s take it one step farther, lets say we have a file of VARs that we source then run the script:

FOO="from a file"

So we edit our script one more time:

source ./vars
echo "This is outputted ${FOO:-"from the script"}

What will happen now?

$ bash script.sh
This was outputted from a file
$ FOO="from the shell" bash run.sh
This was outputted from a file

Well, that’s interesting. So even on the command line, using source you’ll still get the most “local” decaration of the VAR in bash.

Hopefully this show’s the scope of how bash scopes it’s variables, and if you’re like me, and like to have options to run scripts, this’ll help you in the future.