Shift and $# to Manage Arguments

Summary: Use shift to move through passed arguments dynamically.


When writing shell scripts, dealing with command-line arguments is inevitable. Scripts often require flexibility in handling an arbitrary number of arguments—sometimes processing each, sometimes modifying or shifting them as logic dictates. Two key features that make this possible in Bash and other Unix shells are the shift command and the special parameter $#. Let's explore how they work together to help you manage arguments like a pro.


Understanding Positional Parameters

First, when a shell script is invoked with arguments, they’re assigned to special variables:

  • $0 – script name
  • $1 – first argument
  • $2 – second argument
  • ..., etc.

Suppose you invoke your script as:

./myscript.sh foo bar baz

then,

Variable Value
$0 myscript.sh
$1 foo
$2 bar
$3 baz

But what if you don't know in advance how many arguments there will be, or need to process a variable number of them in a loop? This is where $# and shift shine.


What is $#?

$# is a special parameter that tells you how many positional arguments were passed to your script or function. In the previous example, $# would be 3, since there are three arguments.

echo "There are $# arguments."
# Output: There are 3 arguments.

You can use this in conditional statements to check if the right number of arguments were supplied:

if [ "$#" -lt 2 ]; then
    echo "Usage: $0 arg1 arg2"
    exit 1
fi

The Power of shift

shift is a built-in command that reassigns the positional parameters: it "shifts" them to the left by n positions (default is 1). That means $2 becomes $1, $3 becomes $2, etc. Each time you call shift, one argument is removed from the front of the list.

This is incredibly useful for processing arguments one at a time in a loop.

Example: Loop Over All Arguments

Here's a typical example using shift and $# together:

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

How does this work?

  1. The loop checks if there are any arguments left: "$#" greater than 0.
  2. It prints the current first argument ($1).
  3. Calls shift, moving the next argument into $1.
  4. Continues until all arguments are processed.

Run it with:

./myscript.sh one two three

Output:

Processing argument: one
Processing argument: two
Processing argument: three

Advanced Use – Handling Options

Many scripts process options (like -h or --help) using a while loop and shift:

#!/bin/bash

while [ "$#" -gt 0 ]; do
    case "$1" in
        -h|--help)
            echo "Usage: $0 [options] file"
            exit 0
            ;;
        -v|--verbose)
            VERBOSE=1
            ;;
        *)
            FILE="$1"
            ;;
    esac
    shift
done

# Now VERBOSE and FILE are set as per arguments.

This style allows your script to handle options in any order, removing each processed option with shift and moving on.


Summary Table

Special Parameter Usage Example
$# Number of arguments [ "$#" -gt 0 ]
$1, $2, ... Positional arguments echo "$1"
shift Shift argument positions shift 2; echo "$1"

Conclusion

By combining $# to track remaining arguments and shift to move through them, your shell scripts become flexible and robust in processing input. Always remember to check $# before accessing $1 to prevent referencing an empty parameter.

Tip: You can also do shift n to move by n positions at once.

Mastering these tools is key to writing dynamic, user-friendly command-line scripts!