An environment variable is one which can be accessed in all the child or sub shells of the environment, however a local variable can be accessed in only the shell in which it is defined. We saw this in detail in one of our earlier articles, the difference between an environment variable and a local variable.
Let's try something to understand this: $ NUM=20
$ echo $NUM
20
$ ksh
$ echo $NUM
$
In the above example, NUM is a local variable set to 20. On entering the sub-shell or child shell, NUM is not recognized because it is a local variable in the parent shell.
$ export NUM=20
$ echo $NUM
20
$ ksh
$ echo $NUM
20
$ export VAR=30
$ echo $VAR
30
$ exit
$ echo $VAR
$
In the above example, NUM is set as an environment variable using export, and on entering the sub-shell(ksh) we are able to access it. However, the environment variable VAR set in the child shell is not accessible when we went back(exit) to the parent shell.
In UNIX, any environment variables defined in a shell can only be accessed in the child or sub shells, not in the parent shell. However, there are instances when we would like to access an environment variable in the parent shell which is being set in the child shell.
Let us write a sample scripts to simulate the problem. We are going to write 2 scripts, 'first' and 'second'. The contents of files 'first' and 'second' are as shown below :
$ cat first
#!/usr/bin/ksh
echo "In parent"
second
echo "The value of MSG is : $MSG"
$ cat second
#!/usr/bin/ksh
echo "In child"
export MSG="ENVIRON"
On running the script 'first', the following happens:
$ first
In parent
In child
The value of MSG is :
The script 'second' is being called from 'first'. Hence, 'second' is invoked as a sub-shell from 'first'. The variable MSG being set in the 'second' as explained before is not accessible in the parent 'first'.
Solution:
Modifying the scripts 'first' and 'second' as shown below:
$ cat first
#!/usr/bin/ksh
echo "In parent"
second
. env_file
echo "The value of MSG is : $MSG"
$ cat second
#!/usr/bin/ksh
echo "In child"
export MSG="ENVIRON"
printenv | sed 's/^/export /;s/=/=\"/;s/$/\"/' > env_file
Now, on running the script 'first', the following happens:
$ first
In parent
In child
The value of MSG is : ENVIRON
So, we made the parent shell 'first' access the child shell 'second' environment variables.
What did we do:
1. In the script 'second', after setting the environment variable, the list of all environment variables(printenv) is copied to a temporary file env_file.
2. The sed command is used to add the word 'export' at the beginning of every environment variable, and to wrap the variable value with double-quotes. This will enable us to simply run the file in the parent shell to export the variables.
3. In the parent 'first', the script 'second' is called. After the call to the 'second', all the environment variables are being sourced using the dot(.) command, and hence all the variables are now available in the parent as well.
4. On printing the variable VAR, got the value being set in the child and hence accessed the child shell environment variable in the parent.
Enjoy with Shells!!!
PS: This article is written with ksh as example. On trying the above say in csh/tcsh, appropriate modifications need to be made to make it work since the syntax of setting environment variables and sourcing a file are different.