Created as a replacement for the venerable Unix Bourne Shell, Bash is a flexible tool that supports a rich command set and a powerful command language.
The file /etc/profile, if present, is read on start-up, followed by ~/.bash_profile. Some implementations may read ~/.profile if the other two files are NOT present but this behaviour cannot be relied on.
All Bash variables are global, meaning that you can access them from anywhere, but…
When you start a script, Bash forks a new shell and the variables created within the new shell are global to that shell only. This also happens when you create a pipe within a script, all the variables within the pipe are inaccessible outside the pipe.
Take a look at this piece of code:
myfile="FirstFile.txt"
cat $myfile \
| awk command \
| while read VARNAME
do
myfile=$VARNAME
done
In this case, we start out in the current shell so $myfile has the value we assigned to it. At the end of the cat, we pipe into awk. Now we have started a sub-shell so $myfile is no longer in scope. Of course, at this point, we don't care, as the values from $myfile are feeding through the pipe. But what happens in the loop? The intention of this code is to end with $myfile holding a new value (this is a slightly contrived example) but what will be the value of $myfile when we exit the loop?
It will be the original value (“FirstFile.txt”), because the $myfile we loaded in the loop, was in a different shell to the one we think we're in.
However, we can remedy this, quite simply, by making Bash's behaviour work for us:
myfile="FirstFile.txt" RESULTVAR=$(cat $myfile | awk command) for VARNAME in $RESULTVAR do myfile=$VARNAME done
If you follow this through, you'll see that we never move out of the current shell. The $(cat myfile | awk command) starts a child but that child process returns its final value (in this case, a list of files) to the parent, so the exit value of $myfile is available to the parent shell.
This behaviour is good if you understand it and thoroughly bad if you don't.