The main focus of this article is to clearly understand what happens when you run the script vs source the script in bash. First, we will clearly understand how the program is submitted when you call the script in different ways.
NOTE: creating the script with an extension doesn’t matter. Script will run fine even without extensions.
Basically, every script starts with a line called a shebang(#!). The Hash symbol in bash will be interpreted as comments but shebang has a special meaning. It tells bash to submit the program in whatever interpreter you mentioned in shebang.
Below are a sample program and I am specifying bash as my interpreter.
$ cat >> Hello_World.sh #!/usr/bin/env bash echo "Hello world" $ chmod +x Hello_world.sh
Now to run the script, you can do it in two ways.
- Use a relative path to call the script. Move to the directory where the script is present and run ./Hello_world.sh.
- Use the absolute path to call the script. From anywhere in the file system type the full path to the script.
$ ./Hello_world.sh $ pwd $ /home/karthick/Hello_world
Now let’s see what happens when you try to submit your program without shebang. In absence of shebang, the program will be submitted to whatever current shell you are running with, In my case, it is Bash (/bin/bash).
Let me demonstrate an example. I am creating a python script without shebang and when I call the program, bash doesn’t know that it should submit this program to the python interpreter instead it will run the program in the current shell.
$ cat > run-py.py echo $SHELL print("Hello world") $ chmod +x run-py.py $ ./run-py.py
In this case, you can call the program by mentioning on which interpreter it should be submitted to or just add the shebang line which is always recommended.
# which python3 $(which python3) /home/karthick/run_py.py
Now that you know how to call the script, the next step would be to understand what happens when we call the script. When you invoke the script as shown in the above examples it will create a child process (forking) and the script will be submitted to the child process. I ran a sample script that will just run the following command and shows the script is submitted to a child process.
$ ps -ef --forest | grep -i bash
There can be multiple child processes as a part of the script and that depends on our code. It is to be noted that environmental variables created by subscript will be dropped once it gets finished. A child process can access variables created by the parent process by exporting them. But parent process cannot access the variables created by the child process.
Take a look at the below articles to understand more about how variables work and how to export the variables.
- Understanding and Writing ‘Linux Variables’ in Shell Scripting
- Learn Difference Between $$ and $BASHPID in Bash
Sourcing the Script
“Source” is a shell built-in command that reads the file passed as an argument to it and runs the code in the current shell environment. An appropriate use case that you use mostly is modifying your configuration in .bashrc
or .bash_profile
and reloading the changes using the source command.
$ type -a source
There are two syntactic ways to run the source command. You can choose anyone from two syntaxes and it is of personal choice.
$ source FILE_NAME [ARGUMENTS] $ . FILE_NAME [ARGUMENTS]
Let me demonstrate how the source actually works. I am going to create two shell scripts. The first script (Module.sh) is going to hold some variables and functions. The second script (Main.sh) is going to print the variable and call the function.
File Module.sh.
#!/usr/bin/env bash VAR1=$(echo "Welcome to $1") function f1(){ echo “Function f1 is called” }
File Main.sh.
#!/usr/bin/env bash echo $VAR1 f1
Set the execution permission for the script and call the main script “main.sh”. Now, this script will try to find the function f1
and variable VAR1
in the current shell environment and will fail with the command not found.
$ bash main.sh
Now let’s run the source command inside the script which will load the variable and functions into the current shell environment and that will be accessible by “main.sh”.
File Module.sh.
#!/usr/bin/env bash VAR1=$(echo "Welcome to $1") function f1(){ echo "Function f1 is called" }
File Main.sh.
#!/usr/bin/env bash source module.sh Tecmint echo $VAR1 f1
Now run the script again and see.
$ bash main.sh
The source is very useful in bash to follow the modular programming approach in creating our shell scripts. We can break our code into smaller modules and can be used in many programs. In these ways, we can follow the DRY (Don’t Repeat Yourself) principle.
That’s it for this article. We have briefly discussed the difference between sourcing and forking in bash. Go through the article and share your valuable feedback with us.