2

I have observed that only the values of exported variables are appended to the my PATH variable via my Mac OS X .bash_profile. Whereas, the values of locally set variables cannot. Why can't local variables be appended to the path?


“You've misinterpreted something, but what? Post the code that puzzles you. – Gilles yesterday”

Please consider this snippet, where I set the MONGODB variable as:

set MONGODB="/usr/local/mongodb/bin"    
export PATH=${PATH}:${MONGODB}

I source .bash_profile in terminal. I see the following echo:

PATH=~/bin:/usr/bin:/usr/local/bin:/usr/local/sbin:

Whereas, if I export MONGODB instead, and source my .bash_profile, I see the following echo:

PATH=~/bin:/usr/bin:/usr/local/bin:/usr/local/sbin:/usr/local/mongodb/bin

Perhaps, using set is improper?

Loom
  • 3,953
  • 3
    The difference between exported variables and non-exported variables is that only exported variables are visible in programs started by that shell. Your question doesn't make any sense: local variables can be appended to the path. You've misinterpreted something, but what? Post the code that puzzles you. – Gilles 'SO- stop being evil' Mar 14 '11 at 21:48
  • I'm not sure I understand the question, but the whole point of exporting variables is to make them available outside of the current shell. Could you show what you're trying to do? What PATH expression isn't working? How are you starting the new shell? – geekosaur Mar 14 '11 at 21:51

3 Answers3

3
set MONGODB="/usr/local/mongodb/bin"

This is not a variable assignment. (It is one in C shell (csh, tcsh), but not in Bourne-style shells (sh, ash, bash, ksh, zsh, …).) This is a call to the set built-in, which sets the positional parameters, i.e. $1, $2, etc. Try running this command in a terminal, then echo $1.

To assign a value to a shell variable, just write

MONGODB="/usr/local/mongodb/bin"

This creates a shell variable (also called a (named) parameter), which you can access with $MONGODB. The variable remains internal to the shell unless you've exported it with export MONGODB. If exported, the variable is also visible to all processes started by that shell, through the environment. You can condense the assignment and the export into a single line:

export MONGODB="/usr/local/mongodb/bin"

For what you're doing, there doesn't seem to be a need for MONGODB outside the script, and PATH is already exported (once a variable is exported, if you assign a new value, it is reflected in the environment). So you can write:

MONGODB="/usr/local/mongodb/bin"    
PATH=${PATH}:${MONGODB}
2

I will try to explain how shell variables work. It is absolutely possible to append local variables to an environment variable like PATH.

Every running process has a list of environment variables. They are name=value pairs. When a new process is created with fork() it inherits those variables (among other things like open files, user id, etc). In contrast shell variables are an internal shell concept. They are not inherited when creating a new process. You can export shell variables and make them environment variables. When in a shell script you write FOO='bar' that's a shell variable. You can try creating 2 scripts:

# test1.sh
FOO='bar'
sh test2.sh

# test2.sh
echo "${FOO}"

When you execute the first script it sets an internal shell variable then calls fork(). The parent shell process will wait() for the child to finish then the execution continues (if there are more commands). In the child process exec() is called to load a new shell. This new process does not know about FOO. If you modify the first script:

# test1.sh
export FOO='bar'
sh test2.sh

the FOO variable becomes part of the environment and inherited to the forked process. It's important to note that the environment is not global. Child processes can't affect their parent's environment variables.

# test3.sh
sh test4.sh
echo "${PATH}"

# test4.sh
export PATH="${PATH}:/new/path"

Modifications in test4.sh are not visible in test3.sh. Information simply does not go that way. When the child process ends its environment is discarded. Let's change test3.sh:

# test3.sh
source test4.sh
echo "${PATH}"

Source is an built-in shell command. It tells the shell to open a file then read and execute its content. There is only a single shell process. This way the caller can see the modifications to the environment variables and even shell variables.

As you probably know PATH is a special environment variable which tells the shell where to look for other executables. When a new login shell is started it automatically sources .bash_profile. The variables declared in there will be visible. However if in .bash_profile you call other scripts with sh the PATH you set in those scripts will be lost.

stribika
  • 5,454
1

Perhaps, using "set" is improper?

Yes, there's your problem. set doesn't do what you might expect. From the documentation:

This builtin is so complicated that it deserves its own section. set allows you to change the values of shell options and set the positional parameters, or to display the names and values of shell variables.

Note the conspicuous lack of "actually set shell variables" in that list of things it does. Buried in all the docs, you'll find that what it's doing is setting the shell's positional parameters to the arguments you've given. You're just giving one argument, all of MONGODB="/usr/local/mongodb/bin". So $1 gets set to that (and $# gets set to 1, since there's just the one argument).

Score one for anti-mnemonic Unix command names, huh?

So anyway, try just:

MONGODB=/usr/local/mongodb/bin
export PATH=${PATH}:${MONGODB}

and it'll work.

mattdm
  • 40,245
  • Cool! (I wish I could accept more than one answer.) Just to clarify; then: set meta-flag on, would be a proper use of the set built-in, because it sets the meta-flag shell option. – seasonedgeek Mar 15 '11 at 23:53
  • Awesomely, no. That will set $1 to "meta-flag" and $2 to "on". meta-flag is a readline setting, and that set is part of the entirely-different syntax of the readline init file (usually ~/.inputrc). – mattdm Mar 16 '11 at 00:17
  • Oops; positional settings, got it. Good stuff. – seasonedgeek Mar 16 '11 at 00:27