Bash Positional Parameters

By 

Published on

6 min read

Bash Positional Parameters

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 parameters 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’re new to the command line, start with our guide on basic Linux commands .

What Are Positional Parameters?

S When you run a script with arguments, Bash assigns each argument to a numbered variable called a positional parameter:

sh
./script.sh arg1 arg2 arg3

In this example:

  • $0 contains the script name (./script.sh)
  • $1 contains the first argument (arg1)
  • $2 contains the second argument (arg2)
  • $3 contains 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:

~/greet.shsh
#!/bin/bash

echo "Hello, $1!"
echo "You are from $2."

Run the script:

sh
./greet.sh Leah Seattle
output
Hello, Leah!
You are from Seattle.

Parameters Beyond $9

For parameters beyond $9, use curly braces:

sh
echo "The tenth argument is: ${10}"
echo "The eleventh argument is: ${11}"

If you don’t 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:

VariableDescription
$0The name of the script
$1 - $9The 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:

~/showname.shsh
#!/bin/bash

echo "This script is called: $0"
sh
./showname.sh
output
This script is called: ./showname.sh

Counting Arguments ($#)

The $# variable holds the number of arguments passed to the script:

~/count.shsh
#!/bin/bash

echo "You provided $# arguments."
sh
./count.sh one two three
output
You provided 3 arguments.

This is helpful when you want to check if the right number of arguments was given:

~/validate.shsh
#!/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:

sh
for arg in $@; do echo "$arg"; done
for arg in $*; do echo "$arg"; done

But, With quotes, they behave differently:

  • "$@" expands to "$1" "$2" "$3" (separate strings)
  • "$*" expands to "$1 $2 $3" (single string)
~/compare.shsh
#!/bin/bash

echo "Using \"\$@\":"
for arg in "$@"; do
    echo "  - $arg"
done

echo ""
echo "Using \"\$*\":"
for arg in "$*"; do
    echo "  - $arg"
done
sh
./compare.sh "hello world" foo bar
output
Using "$@":
  - hello world
  - foo bar

Using "$*":
  - hello world foo bar

Notice 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:

  • $2 becomes $1
  • $3 becomes $2
  • And so on…
~/shift_example.shsh
#!/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"
sh
./shift_example.sh apple banana cherry
output
Before 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:

sh
shift 3  # Shifts by 3 positions

Processing All Arguments with shift

The shift command is useful for processing arguments one at a time:

~/process_all.shsh
#!/bin/bash

while [ $# -gt 0 ]; do
    echo "Processing: $1"
    shift
done

echo "Done. All arguments processed."
sh
./process_all.sh file1.txt file2.txt file3.txt
output
Processing: file1.txt
Processing: file2.txt
Processing: file3.txt
Done. All arguments processed.

Practical Examples

Example 1: File Backup Script

Here’s a script that backs up a file to a directory you choose:

~/backup.shsh
#!/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 doesn't 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"

Example 2: Simple Calculator

This script does simple arithmetic calculations:

~/calc.shsh
#!/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"
sh
./calc.sh 10 + 5
./calc.sh 20 x 3
output
10 + 5 = 15
20 x 3 = 60

Example 3: Processing Command-Line Options

This script shows how to handle flags and arguments:

~/options.shsh
#!/bin/bash

VERBOSE=false
OUTPUT=""

while [ $# -gt 0 ]; do
    case $1 in
        -v|--verbose)
            VERBOSE=true
            shift
            ;;
        -o|--output)
            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"
done

Positional Parameters in Functions

You can use positional parameters inside functions, too. Each function gets its own set of these parameters:

~/func_params.shsh
#!/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
sh
./func_params.sh test_arg
output
Script 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 aren’t provided:

~/defaults.shsh
#!/bin/bash

NAME="${1:-Guest}"
GREETING="${2:-Hello}"

echo "$GREETING, $NAME!"
sh
./defaults.sh
./defaults.sh Leah
./defaults.sh Leah "Good morning"
output
Hello, Guest!
Hello, Leah!
Good morning, Leah!

The syntax ${VAR:-default} returns default if VAR is unset or empty.

Conclusion

Positional parameters are fundamental to writing flexible Bash scripts that accept command-line arguments. Here are the main things to remember:

  • Positional parameters $1, $2, $3$n, correspond to the position of the parameter after the script’s name.
  • The $0 variable is reserved for the script’s name.
  • $# gives you the argument count.
  • "$@" is the best way to pass all arguments to another command.
  • shift lets you process arguments one at a time.
  • Always validate the number of arguments before using them.

Knowing how to use positional parameters allows you to create Bash scripts that are both powerful and user-friendly. For more details on executing scripts, see our guide on how to run a bash script .

If you have any questions or feedback, please leave a comment.

Tags

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

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