Special Variables in Bash Explained [With Examples]

Last updated: July 2, 2023 | Aditya Harsh

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 VariablesDescription
$0The filename of the current script.
$1…$9Positional 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 "
script output a message that includes the name of the script itself

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
Bash script that prints out the first, second, third, and ninth arguments passed to it.

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
script will output the count of arguments that were passed to the script

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
example script showing usage of $* and $@

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
example script print the Process ID (PID) of the currently running shell to the standard output

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
$?
usage of $? variable in bash

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 $!"
example script print the PID (Process ID) of the most recently executed background pipeline.

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: $-"
bash script showing the use of the special variable $- to display the current 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 "$_"
This prints the value of $_

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: $-"
bash script using special variables

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 $-.

SHARE

Comments

Please add comments below to provide the author your ideas, appreciation and feedback.

Leave a Reply

Leave a Comment