A small Bash report tool may need only one named option and several file operands. Even this simple interface needs a clear boundary between options and filenames. Without it, a filename beginning with a dash may be mistaken for a flag, and unquoted argument expansion may turn one filename containing spaces into several operands.

Prerequisites: Bash on Linux. The parser was tested on GNU Bash 5.2.21. It only prints its interpretation of arguments; it does not open, delete or modify the named paths. No external commands or packages are required by the parser.

Define the command-line grammar

This script recognizes --label VALUE before operands. An explicit -- ends option parsing. The first ordinary operand also ends option parsing, so options cannot be interspersed with file operands. Repeating --label before operands assigns the most recent value. The label must be nonempty, and a following token is accepted as its value even if that token begins with a dash.

Bash documents positional parameters and shifting in its official reference manual. The positional-parameter reference also describes how these arguments are addressed.

Complete parser

Save as args.sh. Calling it with Bash avoids requiring an executable permission change.

#!/usr/bin/env bash
set -eu
label=report
while (( $# )); do
  case "$1" in
    --label)
      if (( $# < 2 )) || [[ -z "$2" ]]; then
        printf '%s\n' 'missing label value' >&2
        exit 2
      fi
      label=$2
      shift 2
      ;;
    --) shift; break ;;
    -*) printf 'unknown option: %s\n' "$1" >&2; exit 2 ;;
    *) break ;;
  esac
done
printf 'label=%s\n' "$label"
printf 'count=%s\n' "$#"
for path in "$@"; do
  printf 'path=%s\n' "$path"
done

Run a normal case

bash args.sh --label 'daily report' -- '-draft.txt' 'two words.txt'

Expected output:

label=daily report
count=2
path=-draft.txt
path=two words.txt

The quotes preserve each argument before the script starts. Inside the script, quoted "$@" preserves the same argument boundaries while iterating. The explicit end-of-options token allows the leading-dash filename to reach the operand loop unchanged.

Check failure behavior

bash args.sh --label
bash args.sh --label ''
bash args.sh --unknown
bash args.sh
bash args.sh a.txt --label late

The first two invocations write missing label value to standard error and exit 2. The third writes unknown option: --unknown and exits 2. With no arguments, the script prints the default label and a count of zero. In the last invocation, the count is three because parsing stopped at a.txt; the later option-looking tokens are ordinary operands.

Edge cases and troubleshooting

The length check prevents a missing second positional parameter from being expanded under set -u. Short-circuit evaluation is part of that protection. Use a fixed format string with printf, keeping user-supplied text in separate arguments.

This output is for human inspection, not a machine-safe filename serialization. A filename containing a newline will span display lines. If another program must consume the operands, pass an argument array or use a deliberate NUL-delimited protocol. When adding a command that opens the paths, check that command's own end-of-options behavior too.

This is a Bash script: invoking it with a different shell can fail on arithmetic and conditional syntax. Explore more Linux tutorials.