Bash Positional Arguments: How to Use $1, $2, $@, and shift

Positional parameters are Bash variables that store the arguments given to a script or function. They help you to write flexible and convenient scripts that can accept input from the command line.
Understanding positional arguments is essential for writing useful Bash scripts. In this guide, you will learn how to access and work with command-line arguments in your scripts. If you are new to the command line, start with our guide on basic Linux commands .
What Are Bash Positional Arguments?
In Bash documentation, these values are called positional parameters, while many users refer to them as positional arguments because they hold the arguments passed by position.
When you run a script with arguments, Bash assigns each argument to a numbered variable called a positional parameter:
./script.sh arg1 arg2 arg3In this example:
$0contains the script name (./script.sh)$1contains the first argument (arg1)$2contains the second argument (arg2)$3contains the third argument (arg3)
Accessing Positional Parameters
Basic Parameters ($1, $2, $3, …)
The most common way to access arguments is through $1, $2, $3, and so on:
#!/bin/bash
echo "Hello, $1!"
echo "You are from $2."Run the script:
./greet.sh Leah SeattleHello, Leah!
You are from Seattle.Parameters Beyond $9
For parameters beyond $9, use curly braces:
echo "The tenth argument is: ${10}"
echo "The eleventh argument is: ${11}"If you do not use braces, $10 would be interpreted as $1 followed by a literal 0.
Special Parameter Variables
Bash provides several special variables for working with positional parameters:
| Variable | Description |
|---|---|
$0 | The name of the script |
$1 - $9 | The first 9 arguments |
${10} … | Arguments 10 and beyond |
$# | The number of arguments |
$@ | All arguments as separate words |
$* | All arguments as a single word |
The Script Name ($0)
The $0 variable contains the name of the script as it was called:
#!/bin/bash
echo "This script is called: $0"./showname.shThis script is called: ./showname.shCounting Arguments ($#)
The $# variable holds the number of arguments passed to the script:
#!/bin/bash
echo "You provided $# arguments."./count.sh one two threeYou provided 3 arguments.This is helpful when you want to check if the right number of arguments was given:
#!/bin/bash
if [ $# -lt 2 ]; then
echo "Usage: $0 <source> <destination>"
exit 1
fi
echo "Copying from $1 to $2"All Arguments ($@ and $*)
Both $@ and $* represent all arguments, but they behave differently when quoted.
Without quotes, they are identical:
for arg in $@; do echo "$arg"; done
for arg in $*; do echo "$arg"; doneWith quotes, they behave differently:
"$@"expands to"$1" "$2" "$3"(separate strings)"$*"expands to"$1 $2 $3"(single string)
#!/bin/bash
echo "Using \"\$@\":"
for arg in "$@"; do
echo " - $arg"
done
echo ""
echo "Using \"\$*\":"
for arg in "$*"; do
echo " - $arg"
done./compare.sh "hello world" foo barUsing "$@":
- hello world
- foo bar
Using "$*":
- hello world foo barNotice that "$@" preserved “hello world” as a single argument, while "$*" joined everything into one string.
Best practice: Use "$@" when you need to pass arguments to another command or iterate over them individually.
The shift Command
The shift built-in command removes the first positional parameter and shifts all others down by one:
$2becomes$1$3becomes$2- And so on…
#!/bin/bash
echo "Before shift:"
echo " \$1 = $1"
echo " \$2 = $2"
echo " \$3 = $3"
shift
echo ""
echo "After shift:"
echo " \$1 = $1"
echo " \$2 = $2"
echo " \$3 = $3"./shift_example.sh apple banana cherryBefore shift:
$1 = apple
$2 = banana
$3 = cherry
After shift:
$1 = banana
$2 = cherry
$3 =Shifting Multiple Positions
You can also use shift to move the positional parameters by more than one position at a time:
shift 3Processing All Arguments with shift
The shift command is useful for processing arguments one at a time:
#!/bin/bash
while [ $# -gt 0 ]; do
echo "Processing: $1"
shift
done
echo "Done. All arguments processed."./process_all.sh file1.txt file2.txt file3.txtProcessing: file1.txt
Processing: file2.txt
Processing: file3.txt
Done. All arguments processed.Practical Examples
Example 1: File Backup Script
Here is a script that backs up a file to a directory you choose:
#!/bin/bash
# Check for required arguments
if [ $# -ne 2 ]; then
echo "Usage: $0 <file> <backup_dir>"
exit 1
fi
SOURCE="$1"
BACKUP_DIR="$2"
# Check if the source file exists
if [ ! -f "$SOURCE" ]; then
echo "Error: File '$SOURCE' not found."
exit 1
fi
# Create a backup directory if it does not exist
mkdir -p "$BACKUP_DIR"
# Create backup with timestamp
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
FILENAME=$(basename "$SOURCE")
cp "$SOURCE" "$BACKUP_DIR/${FILENAME}.${TIMESTAMP}.bak"
echo "Backup created: $BACKUP_DIR/${FILENAME}.${TIMESTAMP}.bak"Create a test file and run the script:
echo "example" > report.txt
./backup.sh report.txt backupsBackup created: backups/report.txt.20260429_092000.bakExample 2: Simple Calculator
This script does simple arithmetic calculations:
#!/bin/bash
if [ $# -ne 3 ]; then
echo "Usage: $0 <number1> <operator> <number2>"
echo "Operators: + - x /"
exit 1
fi
NUM1=$1
OP=$2
NUM2=$3
case $OP in
+) RESULT=$((NUM1 + NUM2)) ;;
-) RESULT=$((NUM1 - NUM2)) ;;
x) RESULT=$((NUM1 * NUM2)) ;;
/) RESULT=$((NUM1 / NUM2)) ;;
*) echo "Unknown operator: $OP"; exit 1 ;;
esac
echo "$NUM1 $OP $NUM2 = $RESULT"./calc.sh 10 + 5
./calc.sh 20 x 310 + 5 = 15
20 x 3 = 60Example 3: Processing Command-Line Options
This script shows how to handle flags and arguments:
#!/bin/bash
VERBOSE=false
OUTPUT=""
while [ $# -gt 0 ]; do
case $1 in
-v|--verbose)
VERBOSE=true
shift
;;
-o|--output)
if [ -z "$2" ]; then
echo "Error: --output requires a file name"
exit 1
fi
OUTPUT="$2"
shift 2
;;
-h|--help)
echo "Usage: $0 [-v] [-o output_file] [files...]"
exit 0
;;
-*)
echo "Unknown option: $1"
exit 1
;;
*)
break
;;
esac
done
# The remaining arguments are files
if [ "$VERBOSE" = true ]; then
echo "Verbose mode enabled"
echo "Output file: ${OUTPUT:-stdout}"
echo "Files to process: $@"
fi
for file in "$@"; do
echo "Processing: $file"
donePositional Parameters in Functions
You can use positional parameters inside functions, too. Each function gets its own set of these parameters:
#!/bin/bash
greet() {
echo "Hello, $1! You are $2 years old."
}
# Script arguments
echo "Script name: $0"
echo "Script argument 1: $1"
# Function arguments (separate from script arguments)
greet "Zoe" 30
greet "Luca" 25./func_params.sh test_argScript name: ./func_params.sh
Script argument 1: test_arg
Hello, Zoe! You are 30 years old.
Hello, Luca! You are 25 years old.Default Values for Parameters
You can set default values for parameters if they are not provided:
#!/bin/bash
NAME="${1:-Guest}"
GREETING="${2:-Hello}"
echo "$GREETING, $NAME!"./defaults.sh
./defaults.sh Leah
./defaults.sh Leah "Good morning"Hello, Guest!
Hello, Leah!
Good morning, Leah!The syntax ${VAR:-default} returns default if VAR is unset or empty.
Conclusion
Positional parameters let Bash scripts read command-line arguments through variables such as $1, $2, $#, and "$@". Use shift when you need to process arguments one at a time, and always validate the expected arguments before using them. For more details on executing scripts, see our guide on how to run a bash script
.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page