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.

  • 1
    Note that using .bashrc is only valid, as long as you use bash as your login shell. It might happen that you start preferring some other shell in the future and would then need to modify the respective rc-file. – Fiximan Mar 7 '16 at 20:52
  • To get a full understanding of which file does what, consider reading: mywiki.wooledge.org/DotFiles – Valentin Bajrami Mar 7 '16 at 21:08
  • Short answer to question #5: environment variables are stored in the memory of each process — that's why it's possible for each process to have a different environment.  See To whom do environment variables belong? for some more information. – G-Man Says 'Reinstate Monica' Mar 7 '16 at 22:06

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.


The environment is not passed via a file but via the stack of newly created processes and the method to achieve this is to pass the environment to the exec() system call.

  • env is an external command (in contrary to shell built in commands) and for this reason, env only prints variables that are exported from the shell.

  • set on the other side lists all shell variables. Some of them are exported.

  • export lists the shell variables that are exported by the shell.


  • .bashrc is not run by login shells, but rather by every interactive (bash) shell. Other shells have other names for this feature. ksh uses .kshrc and the Bourne Shell uses .shrc.

  • .profile is run by login shells. This file is shared between all Bourne Shell compatible shelle.

  • I am a noob so I may need a slightly dumbed-down explanation. I don't know the difference between an "external command" and "built-in shell command." I also don't understand how env is only "exported" variables since I can type env and see a whole list of stuff without having typed anything like export MYMESSAGE="hello world". Would you be able to define your terms (or clarify if my understanding is off/inaccurate/imprecise) – user27186 Mar 7 '16 at 21:17
  • I also don't know what the intended differentiation is between .bashrc being run by "login shells" versus "interactive (bash) shells". I'm not physically opening/running .bashrc interactively or anything. I assumed it runs by itself whenever I login to the shell/terminal/whatever the right terminology is. I know other shells have other features, but for now I'm referring to bash (I updated the OP to reflect this). – user27186 Mar 7 '16 at 21:19

Your understanding is correct.

Your /home/username/.bashrc appends (or overwrites) the settings in /etc/bash.bashrc

There are also some relevant settings in /etc/profile, and you can have a /home/username/.profile but these exist primarily for historical compatibility reasons. (They are an artifact of the Bourne shell, which Bash is based upon.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.