Overview

Now as I’m on holiday and not in Singapore, I cannot use the server in the office. So I want to build a work environment similar to the server on my laptop. The common way is to use a shell script to set the environment and customized commands. Then using source command to run the shell script. In this process, I found that the shell script is a good way to understand the source command.

Script Content

At the beginning part of the shell script, I need to set the project folder path as an environment variable, PROJ_FOLDER. Then I can use this variable to set the path of other folders. The different beginnings of the shell script written by me are shown below.

#!/bin/bash

# Set the environment variable PROJ_FOLDER
AES_FOLDER=$(dirname "$(dirname "$(realpath "$0")")")
export PROJ_FOLDER="$AES_FOLDER"
echo "PROJ_FOLDER set to $PROJ_FOLDER"
#!/bin/bash

# Set the environment variable PROJ_FOLDER
AES_FOLDER=$(dirname "$(dirname "$(realpath "$BASH_SOURCE")")")
export PROJ_FOLDER="$AES_FOLDER"
echo "PROJ_FOLDER set to $PROJ_FOLDER"

The script path is $PROJ_FOLDER/bin/setproj.sh. The only difference between the two scripts is the way to get the path of the script. The first one use $0 and the second one use $BASH_SOURCE. Then I get its grandparent folder by dirname command. At last, I set the environment variable PROJ_FOLDER to the grandparent folder path.

Result of Source Command

Now we use the source command to run the shell script. Which one will set the PROJ_FOLDER correctly? The result is shown below.

PROJ_FOLDER set to /mnt/hgfs
PROJ_FOLDER set to /mnt/hgfs/aes

The first one is the result of the first shell script. The second one is the result of the second shell script. I have to say the first result is wrong. The path it set is the parent folder of the expected PROJ_FOLDER.

But wait, why the first one is wrong? The setproj.sh is at the path PROJ_FOLDER/bin/setproj.sh. After we use $0 to get its position, then we can use dirname to get its parent folder, PROJ_FOLDER/bin. Then we use dirname again to get its grandfather folder, PROJ_FOLDER. So the result should be correct. But why the result is wrong?

Explanation

So which path will the $0 get? Let’s use source command to run the script as below.

#!/bin/bash

# Set the environment variable PROJ_FOLDER
AES_FOLDER=$(realpath "$0")
export PROJ_FOLDER="$AES_FOLDER"
echo "PROJ_FOLDER set to $PROJ_FOLDER"

The output is shown below.

PROJ_FOLDER set to /mnt/hgfs/aes/bash

Hence, now everything is clear. The output shows that the script is run in a subshell, /mnt/hgfs/aes/bash. We can use the $BASH_SOURCE to get the path of the running script. Then we can set the PROJ_FOLDER correctly.

Though the first script is wrong, and took me some time to solve this problem, it is a good way to understand the source command.