Understanding Arguments and Options in Bash Scripts

Author
By Darío Rivera
Posted On in Linux

Arguments and options in bash scripts are useful to make scripts reusable. Today we'll explore how arguments work and how to create maintainable scripts by providing flexibility and reusability.

In Bash scripts, arguments are passed after the script name in the terminal. For example:

./myscript.sh arg1 arg2

How arguments work

The following apply for all scripts:

- $1, $2, ... represent each argument ($1 is arg1, $2 is arg2).
- $@ contains all arguments as a list.
- $# holds the number of arguments passed.

Options and flags

Options make scripts more flexible and user-friendly. Options with no values are commonly referred to as flags. Flags toggle a behavior, usually turning something on or off. Let's look at the following flag examples you might have used before:

./myscript.sh --verbose
./myscript.sh --help
./myscript.sh --quiet

An option expects a value — it’s a key-value pair that modifies how the script behaves. See examples below.

./backup.sh --path=/opt/backups --days=7
./myscript.sh --project-id=1

Manually parsing arguments

There are different ways to parse an argument depending on the intent and behavior we're looking for. One simple way is to use $@ in a for loop to expand each positional argument.

#!/bin/bash

echo "Script name: $0"
echo "Number of arguments: $#"
echo "Arguments: $*"

for arg in "$@"; do
    echo "Processing argument: $arg"
done

The previous script will show the following when executed with three arguments:

user@server:$ ./arguments.sh one two three
Script name: ./arguments.sh
Number of arguments: 3
Arguments: one two three
Processing argument: one
Processing argument: two
Processing argument: three

Let's notice we have used $* that represents all positional arguments as one word. Then, we have used $@ to expand each argument.

Another way to traverse arguments can be done as follows:

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

While we have the same result as the first example, this way is a bit more complex. In Bash, the shift command removes the first positional parameter ($1) and shifts all remaining arguments one position to the left. After each shift, $1 becomes the next argument, $2 becomes the one after that, and so on. The argument count ($#) decreases by one each time.

Parsing flags

Let's start with parsing flags, and we'll care about key-pair options later. While I personally prefer traversing options in a for loop with $@, the most common case is not that one. Let's focus on shift, since you'll encounter more of this in your daily work.

Check the script below. I've introduced a case statement for readability. If you have used it before in other programming languages, you'll encounter this syntax familiar. Let's think of ;; as a break instruction, and *) as a default statement.

#!/bin/bash

echo "Number of arguments: $#"
echo "Arguments: $*"

while [[ $# -gt 0 ]]; do
    case $1 in
        --print-time)
            echo "Current time: $(date)"
            ;;
        --print-os)
            echo "Operating System: $(uname -o)"
            ;;
        *)
            echo "Error: Unknown option $1" >&2
            exit 1
    esac
    shift
done

While you can use each option independently, as follows:

user@server:$ ./flags.sh --print-time
Number of arguments: 1
Arguments: --print-time
Current time: Mon 03 Nov 2025 12:42:26 PM ES

It's important to notice that we can pass multiple flags so that multiple blocks will be executed.

user@server:$ ./flags.sh --print-time --print-os
Number of arguments: 3
Arguments: --print-time --print-os
Current time: Mon 03 Nov 2025 12:36:18 PM EST
Operating System: GNU/Linux

You might not want this, as the user could pass an unknown flag and still execute a portion of the code. In the following example, the code is unpredictable as it shows an error but it prints the time as well.

user@server:$ ./flags.sh --print-time FOO
Number of arguments: 2
Arguments: --print-time FOO
Current time: Mon 03 Nov 2025 12:45:27 PM EST
Error: Unknown option FOO

To solve this, you can either add an exit statement in each case block, or add some variables at the top like the following:

#!/bin/bash

echo "Number of arguments: $#"
echo "Arguments: $*"

print_time=false
print_os=false
while [[ $# -gt 0 ]]; do
    case $1 in
        --print-time)
            print_time=true
            ;;
        --print-os)
            print_os=true
            ;;
        *)
            echo "Error: Unknown option $1" >&2
            exit 1
    esac
    shift
done

if $print_time; then
    echo "Current time: $(date)"
fi

if $print_os; then
    echo "Operating System: $(uname -o)"
fi

With this simple change, the code is more predictable and consistent.

user@server:$ ./flags.sh --print-time FOO
Number of arguments: 2
Arguments: --print-time FOO
Error: Unknown option FOO

Acerca de Darío Rivera

Author

Application Architect at Elentra Corp . Quality developer and passionate learner with 10+ years of experience in web technologies. Creator of EasyHttp , an standard way to consume HTTP Clients.

LinkedIn Twitter Instagram

Sólo aquellos que han alcanzado el éxito saben que siempre estuvo a un paso del momento en que pensaron renunciar.