106

How to set a global environment variable in a bash script?

If I do stuff like

#!/bin/bash
FOO=bar

...or

#!/bin/bash
export FOO=bar

...the vars seem to stay in the local context, whereas I'd like to keep using them after the script has finished executing.

6 Answers 6

168

Run your script with .

. myscript.sh

This will run the script in the current shell environment.

export governs which variables will be available to new processes, so if you say

FOO=1
export BAR=2
./runScript.sh

then $BAR will be available in the environment of runScript.sh, but $FOO will not.

Sign up to request clarification or add additional context in comments.

5 Comments

Be careful with that first one. Without a slash, it will look in your path: use something like '. ./myscript.sh' if you want to ensure it runs a specific one.
source is an alias for .. So you could run source myscript.sh instead, if you wanted to be more explicit.
I am wondering what happens when i run a script with dot and a space. example . myscript
@cNgamba Ask a new question if you can't find it by reading the other answers on this page and/or googling, but this is a common FAQ; see also e.g. unix.stackexchange.com/questions/114300/…
Sorry, but I'm going to downvote this answer b/c the author hasn't incorporated the two excellent comments at the top of the list. I feel they add to the quality of the answer, and if they're not in the answer itself, many people will miss them.
66

When you run a shell script, it's done in a sub-shell so it cannot affect the parent shell's environment(1). You want to source the script by doing:

. ./setfoo.sh

This executes it in the context of the current shell, not as a sub shell.

From the bash man page:

. filename [arguments]
source filename [arguments]

Read and execute commands from filename in the current shell environment and return the exit status of the last command executed from filename.

If filename does not contain a slash, file names in PATH are used to find the directory containing filename.

The file searched for in PATH need not be executable. When bash is not in POSIX mode, the current directory is searched if no file is found in PATH.

If the sourcepath option to the shopt builtin command is turned off, the PATH is not searched.

If any arguments are supplied, they become the positional parameters when filename is executed.

Otherwise the positional parameters are unchanged. The return status is the status of the last command exited within the script (0 if no commands are executed), and false if filename is not found or cannot be read.


(1) The intent of the export command is not to make variables accessible to the parent of a shell, it's to make them accessible to its children.

Let's say you have two shell scripts as follows, first script1.bash:

xyzzy=plugh        # Set the variable.
./script2.bash     # Execute in sub-shell.
. ./script2.bash   # Execute in THIS shell.
export xyzzy       # Mark variable for export.
./script2.bash     # Execute in sub-shell again.

Then the script2.bash script which simply echoes the value:

echo "xyzzy=[$xyzzy]"

If you run that, you'll see that only an exported variable is seen in the sub-shell:

xyzzy=[]           # Non-exported, not seen in sub-shell.
xyzzy=[plugh]      # Non-exported, seen in same shell.
xyzzy=[plugh]      # Exported, seen in sub-shell.

As mentioned, sourcing the script in the context of the current shell means the variable is available without export. It also mans you could change the variable there and have it affect the caller, since that caller is not the parent shell, but the same shell.

4 Comments

Interesting - I've not seen that syntax before. Is this equivalent to source ./setfoo.sh?
It's the same, just faster to type (and more compatible on older systems - ksh has no source command but it does have '.').
Upvoting b/c of the v. good work explaining the (somewhat confusing) syntax. HOWEVER this answer does not actually answer the OP's question re the "GLOBAL" environment variable; (i.e. export <var>).
@Seamus: well, the question was how to change a variable and have that change reflected in the caller, which I think I answered. However, I've added some extra detail on why this works and why export has nothing to do with it. Thanks for the comment, always appreciate constructive suggestions for improvement.
13

source myscript.sh is also feasible.

Description for linux command source:

source is a Unix command that evaluates the file following the command, 
as a list of commands, executed in the current context

6 Comments

Maybe just a tad more detail here. How about a very brief description of what source does?
@PhillipCloud type man source in the terminal and you'll get what you want.
I'm familiar with source. Maybe the OP isn't.
@PhillipCloud I would like some more detail, myself. If you want to edit the answer, you can definitely do that. Help the cause and all that... Thx!
man source may well return No manual entry for source. Try help source instead. This is because source is a command within the bash command language interpreter, so it has no man page of its own. Type help for all commands defined internally by the shell.
|
4
#!/bin/bash
export FOO=bar

or

#!/bin/bash
FOO=bar
export FOO

man export:

The shell shall give the export attribute to the variables corresponding to the specified names, which shall cause them to be in the environment of subsequently executed commands. If the name of a variable is followed by = word, then the value of that variable shall be set to word.

2 Comments

Please, to every beginner in shell scripting: note there isn't any blank between the envvar name, '=' character and the value itself; this wouldn't work: export FOO = /mydir/bar
This merely repeats the code which is already in the question, and which doesn't work. I don't understand why it has received upvotes.
0

A common design is to have your script output a result, and require the cooperation of the caller. Then you can say, for example,

eval "$(yourscript)"

or perhaps less dangerously

cd "$(yourscript)"

This extends to tools in other languages besides shell script.

To adapt your example, if you save this in A.sh in your PATH and chmod +x it,

#!/bin/sh
echo 'FOO=bar'

you can then

eval "$(A.sh)"

to execute the output (in this case, FOO=bar) in the caller's context.

Obviously, always be careful with eval, and only evaluate strings from a trusted source.

A less adventurous solution is to save

#!/bin/sh
echo 'bar'

as B.sh in your PATH; then the calling script can do the assignment itself, without eval:

FOO=$(B.sh)

Notice how A.sh printed an actual snippet of shell script (the assignment expression) whereas B.sh only prints out the value to be assigned, or otherwise for the caller to use as they see fit.

(Obviously, the example scripts are ridiculously trivial placeholders. In real actual use, you'd use these mechanisms when the script you want to call is complex enough that you want to be able to reuse it.)

Comments

-1

In your shell script, write the variables to another file like below and source these files in your ~/.bashrc or ~/.zshrc

echo "export FOO=bar" >> environment.sh

In your ~/.bashrc or ~/.zshrc, source it like below:

source Path-to-file/environment.sh

You can then access it globally.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.