Special Variables
| Since: | All Linux | |
|---|---|---|
| macOS(2001 Cheetah) | ||
| Bash 1.0(1989) |
Bash provides special variables for accessing script arguments, process information, exit status, and more. These are variables you will use frequently when writing shell scripts.
Syntax
Display the script name.
echo $0
Display positional parameters (arguments).
echo $1 $2 $3
Reference all arguments.
echo "$@" # Treats each argument as a separate string echo "$*" # Treats all arguments as a single string
Display the number of arguments.
echo $#
Display the exit status of the last command.
echo $?
Display the PID of the current shell.
echo $$
Display the PID of the last process run in the background.
echo $!
Special Variables
| Variable | Description |
|---|---|
| $0 | The filename of the script (or the shell name). |
| $1 〜 $9 | The 1st through 9th arguments passed to the script. |
| ${10} and beyond | Arguments from the 10th onward require curly braces. |
| $@ | Expands all arguments as separate strings (can be safely quoted with double quotes). |
| $* | Expands all arguments as a single string, separated by IFS. |
| $# | The number of arguments passed. |
| $? | The exit status of the last command (0 = success, 1 or more = failure). |
| $$ | The PID of the current shell process. |
| $! | The PID of the last process run in the background. |
| $_ | The last argument of the previous command. |
| $LINENO | The line number currently being executed. Useful for debugging. |
| $FUNCNAME | An array of the currently executing function names. |
| $RANDOM | Returns a random integer between 0 and 32767 each time it is referenced. |
| $SECONDS | The number of seconds elapsed since the script started. |
Sample Code
Save the following script as script.sh and run it with $ ./script.sh Hello World 3.
This script reads the arguments passed to it.
sample_script.sh
#!/bin/bash echo "Script name: $0" echo "1st argument: $1" echo "2nd argument: $2" echo "Number of arguments: $#" echo "All arguments: $@"
The following example demonstrates this:
bash script.sh Ayanami Rei 3 Script name: script.sh 1st argument: Ayanami 2nd argument: Rei Number of arguments: 3 All arguments: Ayanami Rei 3
Print an error message and exit when required arguments are missing.
sample_check_args.sh
if [ $# -lt 2 ]; then
echo "Usage: $0 arg1 arg2" >&2
exit 1
fi
Run the following command:
bash check_args.sh Shinji Usage: check_args.sh arg1 arg2
Use $? to check the exit status of the previous command. 0 means success; 1 or greater means failure.
sample_exit_status.sh
ls /nonexistent 2>/dev/null echo "ls exit status: $?" ls /tmp > /dev/null 2>&1 echo "ls exit status: $?"
Run the following command:
bash exit_status.sh ls exit status: 2 ls exit status: 0
Use $$ to get the PID of the current shell, and $! to get the PID of a background process.
sample_pid.sh
echo "Current PID: $$" sleep 10 & echo "Background PID: $!"
Run the following command:
bash pid.sh Current PID: 12345 Background PID: 12346
$RANDOM returns a random integer between 0 and 32767 each time it is referenced.
echo "Random: $RANDOM" Random: 27483
The difference between "$@" and "$*" becomes clear when arguments contain spaces.
sample_at_vs_star.sh
args=("Ayanami Rei" "Ikari Shinji")
for a in "${args[@]}"; do echo "[$a]"; done
for a in "${args[*]}"; do echo "[$a]"; done
Run the following command:
bash at_vs_star.sh [Ayanami Rei] [Ikari Shinji] [Ayanami Rei Ikari Shinji]
Common Mistakes
Common Mistake 1: $? is overwritten before it is checked
$? holds the exit status of the most recent command, but it is overwritten by every subsequent command — including echo. Read it immediately or save it to a variable before using it.
ls /nonexistent 2>/dev/null echo "doing something else" echo "exit status: $?" exit status: 0 ($? reflects echo's status, not ls's)
Save the exit status to a variable before anything else.
ls /nonexistent 2>/dev/null ret=$? echo "exit status: $ret" exit status: 2
Common Mistake 2: Using $* instead of $@ loses argument boundaries
"$*" joins all arguments into a single string. When arguments contain spaces, they are merged together and their boundaries are lost. Use "$@" to keep each argument separate.
sample_at_vs_star_mistake.sh
show_args() {
echo "--- using \$*"
for a in "$*"; do echo " [$a]"; done
echo "--- using \$@"
for a in "$@"; do echo " [$a]"; done
}
show_args "Ayanami Rei" "Ikari Shinji"
Run the following command:
bash at_vs_star_mistake.sh --- using $* [Ayanami Rei Ikari Shinji] --- using $@ [Ayanami Rei] [Ikari Shinji]
Notes
$? is essential for checking whether the previous command succeeded. However, it is immediately overwritten after being read, so save it to another variable first for safe use (e.g., ret=$?; if [ $ret -ne 0 ]; then ...).
Wrapping "$@" in double quotes safely handles arguments that contain spaces. Always use "$@" when passing script arguments directly to another command.
For how arguments work inside functions, see Function Arguments and Return Values.
If you find any errors or copyright issues, please contact us.