Bashrc, Env, and Export – Understanding Environment Variables in Bash

bashbashrcenvironment-variablesshellterminal

Disclaimer: Using bash.

I just need some confirmation / correction on my understanding of these things:

  1. env is basically displaying the current environmental variables that are accessible to my current session AND any child sessions (such as if I were to bash into a child session).

  2. If I were to set a new variable such as MYMESSAGE="hello world!" then it would only be visible to the session in which I created it. If I went into a child session, I would not be able to, for example, echo $MYMESSAGE.

  3. I can export MYMESSAGE="hello world!" though to make it accessible to child sessions. export is the same as adding it to whatever env is pulling up.

  4. However, just because you export something, it won't stick if you happen to close out your sessions and restart the terminal. Edit .bashrc in your /home/username/ directory and add any new environmental variables there, since this script is run on login.

Is my understanding correct so far?

Furthermore, I don't fully understand where the details of env comes from. Is the list of environmental variables all stored in some file and then edited/appended to by .bashrc? I'm just trying to understand how all of this works.

Best Answer

You basically got it right, however a few extra points...

There are several "start-up files" bash may run - some for backwards compatibility with the bourne-shell (sh), other depending on how you started bash: Did you log-in to X? Did you log-in to a TTY? Did you start bash in another (bash-)shell? Is bash running as a script (non-interactive)? Thus .bashrc is not always run, nor may it be the only start-up file. However, it's a good idea to "source" (read and execute) .bashrc in the other start-up files too, so the content of your .bashrc is always added. Use man bash and look especially on the part about how bash starts... the FILES-section also list the files bash uses, including all start-up files. For a more in-depth, try info bash.

In addition to you own start-up files, there are corresponding "default" global start-up files in /etc - these are typically read/executed by bash before your own start-up files. There also other programs that defines their own environment-variables in addition to those defined by bash,which may complement or even override those set by bash. Of particular note is X (the GUI), since it will set-up two different sets of environments, depending on whether X is started manually (with xinit or startx) from a VT, or is started by a "display manager" (eg. xdm or kdm) so you can log-in directly into X (X is started when you boot, and you got a dialog-box for username/password in X).

But before bash, X or any other programs starts, much of the environment - environment-variables - you'll be using, will have been set-up, for example by the login command. Much of this you can find in /etc/login.defs and other configuration-files. For example, the PATH-variable will be set-up - and will differ depending on whether you're root or a normal user.

So if you look at the various files and scripts that are ran as part of the boot, init and log-in process; you'll find most of all the variables you can list with env. Some however - like CWD (current working directory) - are set (and updated) automatically by the shell (bash) itself.

When you run a command, what happen is that bash use a system call called fork(). bash basically makes an identical copy of itself, with the exception that the child gets a new PID (Process ID) and that it's PPID (Parent PID) is that of it's "mother". Else they're identical - even including the environment-variables... assuming the variable in question was made inheritable by first exporting it. You now got two copies of bash. Then another system-call -exec() - is used, which basically replaces the bash-program "in memory" for the child bash-process, with another program - for example with ls, ps or mutt (whatever you typed)... but the environment-variables remains, so the new program inherits it's environment from bash. This child now controls your terminal (unless you put the command in the background with &) until it terminates, while your original bash-shell (basically) sleeps. When the command terminates, you return to your original bash-shell, which is ready for another command.

Related Question