Sometimes we need to think like the command line shell in order to understand how things are done in the background, this would make debugging a breeze.
In this guide, you would learn all the various ways the shell script can be run, and the understanding of how the operations are done in the background with examples.
There are four ways to run a shell script on the command line, let’s say we have a shell called myscript.sh, and it has been made executable (that is you have added the execution permission bit), you can run the script the following ways:
1.) Using File Name
This is the direct method, where you type the name of the script, and it performs the intended operation.
Let me explain what happens when you do that: Typically, before you run a script, the first thing is to log in to your shell environment (i.e your login shell, the shell that starts when you log in).
So, when you type the name of the script by itself and hit enter. What happens is that a new copy of the shell is loaded into memory, meaning you have two copies practically, one is your login shell which is temporary on hold while the other one runs the script in the background.
This is the way GNU/Linux or Unix-like system treats scripts, it creates an instance of your shell and performs the intended operation of the script on the second shell.
This is the point it gets interesting, if any variable is set, that is if a variable holds a value during the running of the script, then the value of the variable is immediately lost as soon as the shell script stop running, it kinda makes sense since the shell running the script is in memory, and as soon as it completes its operation, it unloads from memory, and any value in the script is immediately lost.
Let’s take a quick example, suppose we have the following script:
#!/bin/bash
greeting="Hello Bro"
echo $greeting
I have saved the script with myscript.sh, and I have added an execution permission using chmod +x myscript.sh
So, when I run the script "myscript.sh", I get the following output:
user@server:~/bin$ myscript.sh
Hello Bro
Cool right, here is where thing get a little more interesting, remember I declared the string "Hello Bro" into a variable $greeting, so, if I echo the $greeting into the command line shell, I should get out the value back right? let's try:
user@server:~/bin$ echo $greeting
Opps! I got an empty line, and here's why:
The "greeting" variable was set in the second shell, the forked shell that was use to execute the script, and as soon as the shell completes it's operation, it unloads all the script in its memory, and thus any variable value stored are lost, it is as simple as that.
The important thing to remember about this is that if you do not set any variable during the execution of your shell script. if you execute the script just by typing its name in the command line, which then gives a second shell to execute it while that one is on hold, these variables won't be set in the original shell.
2.) Specifying the Shell Interpreter Along with The File Name
The second method is very similar to the first method, the only difference is that you need to specify the shell interpreter followed by the file name, e.g
sh myscript
for sh interpreter
bash myscript
for bash interpreter
and so on...
This means you want to run a script called myscript, technically, this is the same as method 1 but in this case, the file does not need to be made executable, all the process that happens in method 1 applies to this too, i.e the variable or value does not persist in the original shell once the execution is completed.
Irrespective of what is being used as shebang, the interpreter which you have specified will be used for execution. You can use any interpreter (sh, ksh, bash, csh, etc.,).
Execute Shell Script Using . (dot space and file name) (Sourcing)
The third method is slightly different, you type a dot, space, and the script name, e.g:
. myscript
The builtin source command is a synonym for the . (dot). If you are not comfortable with the “dot space filename” method, then you can use the source command as follows:
source myscript
The reason this is different from method 1 and 2 is that the no second shell is forked or loaded into memory, the script is executed by your current shell, that is your current logged in shell. So, if any variable is set in this script, the value still persists after the script has finished execution.
Let’s take a quick example, suppose we have the following script:
greeting="Hello Bro"
echo $greeting
I have saved the script with myscript.sh, so, when I run the script "myscript", I get the following output:
user@server:~/bin$ . myscript
Hello Bro
If you now echo the $greeting into the command line shell, you should still get the value back, since the values still persist in the current shell memory.
Using the Exec Method
The fourth method of running a script is using the exec method, e.g
exec myscript
When you run this, the current shell you are currently using terminates, which them spawn a new shell in its place to execute the script, and when the script is done, you won't have anywhere to log back in since you are logged out right off the bat.
This is useful in the scenario where you don't want a user to access the shell terminal, for example, you can add "exec myscript" at the end of the user .profile, so, what happens is when the user logs in, the .profile would be run by the shell and when it gets to the last line "exec myscript", the log-in shell would terminate, which would mean that the user won't be able to see the shell terminal, and in its the place the myscript program would be run.
These are the four methods, and I hope you understood it.