Tuesday, October 2, 2007

Shell script sourcing (calling a shell script from within another shell script)

Shell script sourcing (calling a shell script from within another shell script)


In this article I will discuss what happens when you can a shell script from within a shell script.

lets have a shell script abc.sh in /tmp directory


rakesh@unix:) cat /tmp/abc.sh
#The content of the file is:
export VAR="12345"


You can call a shell script by putting a "." before the file path.

e.g,

rakesh@unix:)./tmp/abc.sh


if you are already in /tmp directory, you can run the abc.sh as

rakesh@unix:)./abc

This way the script will successfully execute and end. What you would expect is that the script would have set the value of VAR="12345".

so if you do:


rakesh@unix:) echo $VAR


you see nothing. Surprised!!!!

But, don't panic. Nothing to worry about. This happened because when you execute/run the script by putting a "." (period) in front of the file path, then the script is called in a sub-shell, and what ever the variables are set by the called script are visible only to the sub-shell or any other sub-shells created by the called script. (Please read the above explanation once again.)

Lets consider another scenario (Similar to the above scenario)

Suppose you want to access $VAR in def.sh, which is set to "12345" when abc.sh is executed by def.sh, and want to modify it or use it. Lets just try to echo it for the moment after calling abc.sh

rakesh@unix:) cat def.sh
VAR=""
echo "I am inside def.sh"
echo "executing abc.sh"
./abc.sh
echo "abc.sh executed"
echo "$VAR"
#end of def.sh



Now, execute def.sh

rakesh@unix:) ./def.sh
I am inside def.sh
executing abc.sh
abc.sh executed


Yes, you are right. $VAR is not set.

Now lets edit the def.sh to:


rakesh@unix:) cat def.sh
VAR=""
echo "I am inside def.sh"
echo "executing abc.sh but not as a child"
. abc.sh
#period space abc.sh, can also be executed as . ./abc.sh
echo "abc.sh executed"
echo "$VAR"
#end of def.sh



and execute def.sh again
rakesh@unix:) ./def.sh
I am inside def.sh
executing abc.sh
abc.sh executed
12345



See that result? Can you guess what happened when you changed ./abc.sh to . abc.sh? Don't worry, read on.

when we call a script with a period in the front and then a space, as we did above.

rakesh@unix:) . abc.sh

or

rakesh@unix:) . ./abc.sh

Then the commands in the called script (abc.sh) are treated as if the commands were in the calling (parent) def.sh script. So, whatever the variables are created, modified or exported by the called script are visible to the calling parent (def.sh) script.

Now, suppose if you executed abc.sh script as . abc.sh (period space filename) and abc.sh has exit 0 at its end. Can you guess what would be the result?


rakesh@unix:) cat abc.sh
#The content of the file is:
VAR="12345"
exit 0


Execute def.sh script


rakesh@unix:) ./def.sh
I am inside def.sh
executing abc.sh


Yes, the last two commands in def.sh script were skipped. And the reason is quite simple. Since we executed abc.sh in parent shell and abc.sh stopped because of exit it actually stopped the execution of def.sh

because UNIX treated def.sh as under:

VAR=""
echo "I am inside def.sh"
echo "executing abc.sh but not as a child"
#The content of the file is:
VAR="12345"
exit 0
#period space abc.sh, can also be executed as . ./abc.sh
echo "abc.sh executed"
echo "$VAR"
#end of def.sh



So, it is quite obvious to see why last two echo commands were skipped after encountering exit 0.

Now, suppose you execute abc.sh as child of def.sh.


rakesh@unix:) cat def.sh
VAR=""
echo "I am inside def.sh"
echo "executing abc.sh"
./abc.sh
echo "abc.sh executed"
echo "$VAR"



Execute def.sh

rakesh@unix:) ./def.sh
I am inside def.sh
executing abc.sh
abc.sh executed



So, the output is self explanatory. The last two echos after ./abc.sh were executed because the child shell got terminated when it encountered exit 0, but not the parent shell. Not, to mention that $VAR is blank because it is not visible to the parent shell.


So, to sum up, executing a shell script as ./ executes the in a child shell and the variables set or modified in child shell are not visible to parent shell (calling shell).

Also, if the is called as . ./ or . , then the variables set or modified will actually be set by the calling/parent script. Obviously, the variables will be visible to it if its is actually set by it.


Hope it helped someone.

Thank you for reading.

Kind regards,

Rakesh Gupta

No comments: