Setting PATH vs. exporting PATH in ~/.bash_profile

130,501

Solution 1

To answer your questions specifically:

  1. export does set the $PATH explicitly.

  2. No. export sets environment for child processes, but $PATH is already set for the current environment. So, in the second example, when the command is read-in - and before export is executed - the current environment's value for $PATH is expanded into the $PATH word.

  3. You should use whichever is necessary and/or comfortable for you. Neither makes any difference functionally, so this is primarily a question of style.

POSIX defines the export builtin so:

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.

From another of my answers:

There is little difference between declaring a shell variable and an environment variable. Because export is a builtin it declares an environment variable for the process next invoked, but if you don't invoke one that process remains the shell, and so your variable is twice evaluated.

You can remove all exports without any effect at all on exported variables so long as you don't use export to twice evaluate. By twice evaluate I mean:

var1=var2 
export "${var1}=var3"
echo "$var2"
var3

Instead just use:

set -a 

...at the top of the script. All variables defined thereafter will be automatically exported - which would include variables you might not have previously exported. Alternatively you could only set -a for a portion of the script and later set +a to unset it - it could also work as function.

But subshells automatically inherit variable values anyway, so:

var1=value
( echo "$(echo "$var1")" )
value

export makes no difference in that case.

But if your script calls another script, or any other executable that interprets values you've exported and you cease to export them, then those values will no longer be available in their environment. In the following example I use the shell variable $PS1 - which defines the contents of an interactive shell's prompt - to demonstrate how variations on exported variables affect child processes.

export PS1="$(printf "this is another executable\n > ")"
echo exit | sh -i

###OUTPUT###

this is another executable
 > exit
exit

But ...

PS1="$(printf "this is another executable\n > ")"
echo exit | sh -i

###OUTPUT###

sh-4.3$ exit
exit

But then again, if you explicitly declare environment variables while invoking a process...

PS1="$(printf "this is another executable\n > ")"
{
echo exit | PS1=$PS1 sh -i
echo exit | sh -i
}

###OUTPUT###

this is another executable
 > exit
exit
sh-4.3$ exit
exit

Any of the ENV files first invoked by a shell such as .bashrc or .profile will set variable values for the life of that shell. So any variables that are set and exported within those files will maintain that export characteristic and be exported to all child processes invoked by that shell for the life of the shell or until they are unset.

It is notable, though, that bash extends the export builtin somewhat to include the -n option - which enables you to remove the export attribute from a variable without unsetting it, but this is not portable behavior.

Solution 2

Here's a similar thread.

A short answer:

https://superuser.com/a/153378/333431

Exported variables get passed on to child processes, not-exported variables do not.

This means you should export your variables, if you intend to use them in subshells.

You can test this:

$ TEST="im_not_here"
$ echo $TEST
im_not_here
$ bash -c 'echo $TEST'
<empty output>
$ export TEST2="im_here"
$ echo $TEST2
im_here
$ bash -c 'echo $TEST2'
im_here
Share:
130,501

Related videos on Youtube

njboot
Author by

njboot

I enjoy learning from and contributing to the StackExchange community.

Updated on September 18, 2022

Comments

  • njboot
    njboot over 1 year

    What's the difference and which is better to use when customizing my bash profile? Documentation on the export command is scarce, as it's a builtin cmd.

    Excerpt from version 1 of my ~/.bash_profile:

    #PATH
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:$HOME/bin
    
    #add Homebrew’s sbin to PATH
    export PATH=/usr/local/sbin:$PATH
    

    Output from: echo $PATH /usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Users/njboot/bin

    Excerpt from version 2:

    #PATH
    PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:$HOME/bin
    
    #add Homebrew’s sbin to PATH
    export PATH=/usr/local/sbin:$PATH
    

    Output from echo $PATH is the same as in version 1. env is the same as well.

    So:

    • 1) What's the benefit of using export vs. setting PATH explicitly?
    • 2) Is there any functional difference between version 1 and version 2 when applied?
    • 3) Which should I use and why?
  • mikeserv
    mikeserv almost 10 years
    You should clarify what you mean by subshells. var=val ; (echo $var) still yields val.
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' almost 10 years
    And yet PATH=/usr/local/sbin:$PATH would work equally well without the export: once a variable is exported, it stays exported, and further assignments modify the environment variable. Furthermore, to clarify mikeserv's comment, you don't need export to use variables in subshells, you need them to use them in child programs. Subshell is a technical term, meaning a forked copy of the running shell. (echo $var) runs echo $var` in a subshell and sees the original shell's internal variable; sh -c 'echo $var' runs echo $var in a child program and only sees environment variables.