Parham
Parham

Reputation: 3482

Why can you set environment variables in Bash functions but not in the script itself

Why does this work:

# a.sh
setEnv() {
    export TEST_A='Set'
}

when this doesn't:

# b.sh
export TEST_B='Set'

Ex:

> source a.sh
> setEnv
> env | grep TEST_A
TEST_A=Set
> b.sh
> env | grep TEST_B

I understand why running the script doesn't work and what to do to make it work (source b.sh etc), but I'm curious to why the function works. This is on OS X if that matters.

Upvotes: 8

Views: 15806

Answers (3)

mklement0
mklement0

Reputation: 439832

I understand why running the script doesn't work and what to do to make it work (source b.sh etc)

So you already understand the fact that executing b.sh directly -- in a child process, whose changes to the environment fundamentally won't be visible to the current process (shell) -- will not define TEST_B in the current (shell) process, so we can take this scenario out of the picture.

I'm curious why the function works.

  • When you source a script, you execute it in the context of the current shell - loosely speaking, it is as if you had typed the contents of the script directly at the prompt: any changes to the environment, including shell-specific elements such as shell variables, aliases, functions, become visible to the current shell.

  • Therefore, after executing source a.sh, function setEnv is now available in the current shell, and invoking it executes export TEST_A='Set', which defines environment variable TEST_A in the current shell (and subsequently created child processes would see it).

  • Perhaps your misconception is around what chepner's helpful answer addresses: in POSIX-like shells, functions run in the current shell - in contrast with scripts (when run without source), for which a child process is created.

This is on OS X if that matters.

Not in this case, because only functionality built into bash itself is used.

Upvotes: 6

chepner
chepner

Reputation: 532093

Executing a function does not, in and of itself, start a new process like b.sh does.

From the man page (emphasis on the last sentence):

FUNCTIONS
       A shell function, defined  as  described  above  under  SHELL  GRAMMAR,
       stores  a  series  of commands for later execution.  When the name of a
       shell function is used as a simple command name, the list  of  commands
       associated with that function name is executed.  **Functions are executed
       in the context of the current shell;  no  new  process  is  created  to
       interpret  them  (contrast  this with the execution of a shell script).**

Upvotes: 9

Inian
Inian

Reputation: 85845

You need to understand the difference between sourcing and executing a script.

  • Sourcing runs the script from the parent-shell in which the script is invoked; all the environment variables are retained until the parent-shell is terminated (the terminal is closed, or the variables are reset or unset), whereas

  • Execute forks a new shell from the parent shell and those variables including your export variables are retained only in the sub-shell's environment and destroyed at the end of script termination.

i.e. the sub-shell ( imagine it being an environment) created in the first case to hold the variables are not allocated in scope of a separate child environment but are just added in the parents' ( e.g. imagine an extra memory cell, maintained by the parent ) environment which is held until you have the session open. But executing a script is, imagine a simple analogy, calling a function whose variables are in stored in stack which loose scope at the end of function call. Likewise, the forked shell's environment looses scope at the end of its termination.

So it comes down to this, even if you have a function to export your variable, if you don't source it to the current shell and just plainly execute it, the variable is not retained; i.e.

# a.sh
setEnv() {
    export TEST_A='Set'
}

and if you run it in the shell as

bash script.sh    # unlike/NOT source script.sh
env | grep TEST_A
                  # empty

Upvotes: 12

Related Questions