Sagar.BlogArticle
All posts
All posts
Bash

shift — Processing Arguments Sequentially

The shift command moves positional parameters left, letting you consume arguments one at a time. Useful for custom option parsing and processing variable-length argument lists.

January 26, 20265 min read
BashshiftArgumentsScripting

shift moves the positional parameters one step to the left: $2 becomes $1, $3 becomes $2, and so on. $1 is discarded, and $# decreases by 1. It's how you consume arguments one at a time in a loop.

Basic shift

#!/usr/bin/env bash
# Called as: ./script.sh a b c d

echo "Before:"
echo "$# = $#"    # 4
echo "$1 = $1"    # a
echo "$2 = $2"    # b

shift

echo "After shift:"
echo "$# = $#"    # 3
echo "$1 = $1"    # b (was $2)
echo "$2 = $2"    # c (was $3)

shift 2            # shift by 2

echo "After shift 2:"
echo "$# = $#"    # 1
echo "$1 = $1"    # d

Processing All Arguments with shift

#!/usr/bin/env bash
# Sum all numeric arguments

total=0
while [[ $# -gt 0 ]]; do
    total=$(( total + $1 ))
    shift
done
echo "Total: $total"

# Usage: ./sum.sh 1 2 3 4 5  →  Total: 15

Manual Flag Parsing with shift

#!/usr/bin/env bash

verbose=false
output=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        -v | --verbose)
            verbose=true
            shift
            ;;
        -o | --output)
            if [[ $# -lt 2 ]]; then
                echo "ERROR: -o requires an argument" >&2
                exit 1
            fi
            output="$2"
            shift 2          # shift past flag AND its value
            ;;
        --output=*)
            output="${1#--output=}"   # strip --output= prefix
            shift
            ;;
        --)
            shift
            break            # everything after -- is a positional arg
            ;;
        -*)
            echo "Unknown flag: $1" >&2
            exit 1
            ;;
        *)
            break            # first non-flag argument
            ;;
    esac
done

# Remaining $@ are positional args
echo "Verbose: $verbose"
echo "Output: $output"
echo "Remaining args: $@"

shift 2 for options with arguments

When an option takes an argument (like -o file.txt), you need shift 2 — once to discard the flag (-o) and once to discard its value (file.txt). Forgetting to shift by 2 causes the next iteration to try to parse file.txt as a flag.

Quick Check

A script receives args `one two three`. After `shift 2`, what is `$1`?

Exercise

Write a script install.sh that accepts:

  • --prefix /path or -p /path → installation prefix (default /usr/local)
  • --dry-run or -n → print what would be done without doing it
  • One positional argument: the package name

Use shift-based manual parsing. Print a summary: "Installing PACKAGE to PREFIX (dry: true/false)"