Shell – Difference Between Shell Variables and Environment Variables

command lineenvironment-variablesshell

I actually did not know there are two different types of variables I can access from the command line. All I knew is, that I can declare variables like:

foo="my dear friends"
bar[0]="one"
bar[1]="two"
bar[2]="three"

or accessing them with a $ sign, like:

echo $foo
echo ${bar[1]}

or using inbuilt variables, like:

echo $PWD
PATH=$PATH:"/usr/bin/myProg"

Now, I hear there are two (at least?) types of variables: shell variables and environment variables.

  • What is the purpose of having two different types?
  • How do I know which type a variable is?
  • What are the typical usages for each one?

Best Answer

Environment variables are a list of name=value pairs that exist whatever the program is (shell, application, daemon…). They are typically inherited by children processes (created by a fork/exec sequence): children processes get their own copy of the parent variables.

Shell variables do exist only in the context of a shell. They are only inherited in subshells (i.e. when the shell is forked without an exec operation). Depending on the shell features, variables might not only be simple strings like environment ones but also arrays, compound, typed variables like integer or floating point, etc.

When a shell starts, all the environment variables it inherits from its parent become also shell variables (unless they are invalid as shell variables and other corner cases like IFS which is reset by some shells) but these inherited variables are tagged as exported1. That means they will stay available for children processes with the potentially updated value set by the shell. That is also the case with variables created under the shell and tagged as exported with the export keyword.

Array and other complex type variables cannot be exported unless their name and value can be converted to the name=value pattern, or when a shell specific mechanism is in place (e.g.: bash exports functions in the environment and some exotic, non POSIX shells like rc and es can export arrays).

So the main difference between environment variables and shell variables is their scope: environment variables are global while non exported shell variables are local to the script.

Note also that modern shells (at least ksh and bash) support a third shell variables scope. Variables created in functions with the typeset keyword are local to that function (The way the function is declared enables/disables this feature under ksh, and persistence behavior is different between bash and ksh). See https://unix.stackexchange.com/a/28349/2594

1This applies to modern shells like ksh, dash, bash and similar. The legacy Bourne shell and non Bourne syntax shells like csh have different behaviors.