1. Introduction
In Bash, special variables are those variables that are intentionally set by the shell internally so that it is available to the user. These variables are also referred to as special parameters. Special variables are mainly assigned with the task of storing information related to the shell or the environment. They are ideal when it comes to writing Bash scripts because their role is to provide access and manipulate important information about the executing shell or the script.
2. List and Explanation of Special Variables in Bash
The following table gives a quick overview of 9 special variables in Bash.
Special Variables | Description |
---|---|
$0 | The filename of the current script. |
$1…$9 | Positional parameters storing the names of the first 9 arguments |
$$ | The process id of the current shell. |
$# | The number of arguments supplied to a script. |
$* | Stores all the command line arguments. |
$@ | Stores the list of arguments as an array. |
$? | Specifies the exit status of the last command or the most recent execution process. |
$! | Shows the id of the last background command. |
$- | Shows the options set used in the current bash shell. |
2.1. $0 - The Name of the Script
The special Bash variable $0 is meant to hold the name of the script. Let us try an example:
Example:
#!/bin/bash
echo "I am running the script $0 "
We have a simple script that displays the name of the file when executed
2.2. $1 to $9 - Arguments to the Script
We can refer to the arguments passed to the script by using the special variables $1 to $9.
Example:
#!/bin/bash
echo argument 1 is $1
echo argument 2 is $2
echo argument 3 is $3
echo argument 9 is $9
Run this script as:
./splVar2.sh a b c d e f g h i
The $0 stores the name of the script. $1 holds the first argument which is "a" and so on. Thus, the last value "i" will be present in the $9 variable.
2.3. $# - Number of Arguments
To get the count of arguments we generally would use loops. We iterate over all the arguments passed to the script and increment the count by 1 every time. Instead of that, we just need to employ the $# variable.
Example:
#!/bin/bash
echo "Count of arguments $#"
Now let us run this script using the command:
./splVar3.sh a b c d e f g
To get the count, we have supplied 7 arguments to the script. The script uses the special variable $# to print the count as 7.
2.4. $* and $@ - All Arguments
Bash uses $* and $@ to expand into the full list of positional arguments $1 $2 $3. This eases the passing and handling of positional parameters whether be it scripts or functions. We have already seen in detail how $* differs from $@. Without the use of double quotes, both $@ and $* have the same effect.
Example:
#!/bin/bash
echo "----------------Using $@----------------"
for input in $@
do
echo "$input "
done
echo "----------------Using $*----------------"
for input in $*
do
echo "$input "
done
Now let us run this script using the command:
./splVar4.sh a b c d
When we execute, the $@ as well as the $* expand the arguments available to the script. In every iteration, it picks the argument and prints it on the terminal. This saves us from having to pick up the positional parameters $1, $2… $n individually.
2.5. $$ - Process Identification Number (PID)
The $$ variable is meant to store the Process ID (PID) of the current shell. This is a unique identifier assigned by the operating system to each running process. All we need to do is have the $$ in our script, whenever we want to fetch the PID.
Example:
echo $$
echo "Making an entry" >> myfile-$$.txt
As we are aware, PID is a unique number, we use the $$ variable in our script to generate a unique filename.
2.6. $? - Exit Status of the Last Command
When we want to check the status of the execution of the last command execution, we have to rely on the $? variable. The output returned is an integer. 0 indicates success and anything other than a 0 implies failure.
Example:
pwd
$?
abc
$?
In the first scenario, we are executing the pwd command to get the path of the working directory. As this command has executed successfully, the $? returns 0. In the next scenario, as abc is not a valid command, the integer returned in this case is a non-zero number. We often use this feature to develop conditions in order to process files.
2.7. $! - PID of the Last Background Command
Bash has the special variable $! to get the PID of the last background command that was executed. We can run any command in the background. We need to append the ampersand (&) at the end. This command then executes in a subshell and the shell continues to execute the next command without waiting for the background command to finish.
Example:
sleep 10 &
echo "PID of the command in the background is $!"
The sleep command executes in the background since the & symbol is appended to it. The shell immediately comes back and executes the next command, which prints the PID of the background command using the $! variable. When there are multiple background commands, the $! variable gets modified by the PID of the last executed background command.
2.8. $- - Current Option Flags
The special variable $- displays the current options set for the shell. These options control the behavior of the shell. The commonly used options are:
- i - Causes the shell to run in interactive mode.
- e - Causes the shell to exit immediately if any command exits with a non-zero status.
- x - Causes the shell to print each command to the terminal before executing it.
- u - Causes the shell to treat unset variables as an error and exit.
Example:
!/bin/bash
echo "Current shell options: $-"
set -e
echo "When e is set"
echo "Current shell options: $-"
set +e
echo "When e is unset"
echo "Current shell options: $-"
We are initially fetching the current shell options using $-.
Then enable the e option using the set -e command. This makes the shell exit immediately if any command exits with a non-zero status. We get the updated shell options using $- again.
We finally disable the e option using the set +e command, and print the latest shell options.
2.9. $_ - Most Recent Parameter
The special variable $_ contains the last argument of the previous command that was executed.
Example:
echo "Good day"
echo "$_"
We first execute the echo command to print "Good day". The next command echo $_ prints the value held by the $_ variable. It contains the last argument of the most recently executed command. Hence we get to see "Hello, world!" on the terminal for the second time.
$_ only contains the last argument of the previous command, not the entire command itself. If the previous command had multiple arguments, $_ would contain only the last argument.
3. Example Script Using Special Variables
In this section, we are going to take an example and bring every variable we have seen so far into play.
!/bin/bash
usage()
{
# Use of $0
echo "Usage: $0 <file1> [<file2> ... <fileN>]"
}
# Use of $#
if [ "$#" -lt 1 ]
then
echo "No file specified."
usage
exit 1
fi
# Use of $1
echo "Number of arguments to the script=$# and first argument is $1"
# Use of $@
for file in "$@"
do
if [ ! -f "$file" ]
then
echo "[ERROR] File $file doesn't exist"
continue
else
currentDate=`date +%d-%m-%y`
currentTime=`date +%H-%M`
# Use of $$
cp $file ${file}_$$_${currentDate}_${currentTime}
# Use of $?
RC=$?
if [[ ${RC} -eq 0 ]]
then
echo "Copied $file to ${file}_$$_${currentDate}_${currentTime}"
echo "Its first line is: "
# Use of $$
head -1 ${file}_$$_${currentDate}_${currentTime}
fi
fi
done
# Use of $-
echo "Current shell options: $-"
1. The usage function displays how to run the script. We have used the $0 variable to display the name of the script.
2. We count the number of arguments available to the script using $#. No arguments are supplied if it is less than 1. In this case, we call the usage method and terminate the script.
3. If the arguments are more than 1, display the count and the first argument using the $1 variable,
4. Then we read all the arguments using $@ one by one using the for loop.
5. For every entry, we check if the specified input is a file or not. If it is not a file, we display an error message and jump to the next iteration using the continue statement.
6. If it is a file, we extract the current date and time from the Bash date command.
7. We then create a backup copy the file with a unique name using the $$: file_<dateDD-MM-YYYY>_<timeHH-MM>
8. We then verify the exit status of the cp command using $?. If its numerical value is zero, it indicates that the command succeeded.
9. We finally display the successful copy message.
10. We repeat this for the next entry in the for loop.
11. After the loop is terminated, we display the current shell options using the special bash variable $-.
Comments