How do I parse command line arguments in Bash?

To parse command-line arguments in Bash, you can use positional parameters ($1, $2, etc.), the getopts built-in (for short options), or the external getopt command (for long options). Below is a detailed guide with examples.

1. Basic Argument Parsing

Access arguments directly using positional parameters:

  • $1, $2, …: Individual arguments.
  • $#: Total number of arguments.
  • $@: All arguments as an array.
  • $0: Script name.

Example: Simple Script

#!/bin/bash
echo "Script Name: $0"
echo "First Argument: $1"
echo "Second Argument: $2"
echo "All Arguments: $@"
echo "Total Arguments: $#"

Usage:

./script.sh arg1 arg2

2. Using getopts for Short Options

getopts is ideal for parsing short options (e.g., -a, -b value).
It supports:

  • Options with required values (-f filename).
  • Error handling for invalid options.

Example: Parse -a and -f <file>

#!/bin/bash
while getopts ":af:" opt; do
  case $opt in
    a)
      echo "Option -a triggered"
      ;;
    f)
      echo "Option -f has value: $OPTARG"
      ;;
    \?)
      echo "Invalid option: -$OPTARG"
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument."
      exit 1
      ;;
  esac
done

# Shift processed options, leaving non-option arguments
shift $((OPTIND -1))

echo "Remaining arguments: $@"

Usage:

./script.sh -a -f input.txt remaining_arg

Key Points:

  • :af:: Options string where:
  • a is a flag without arguments.
  • f: expects a value (colon : indicates required argument).
  • OPTARG: Value of the option’s argument (e.g., input.txt for -f).
  • OPTIND: Index of the next argument to process.
  • shift $((OPTIND -1)): Moves positional parameters past the options.

3. Using getopt for Long Options

The external getopt command (not getopts) supports long options (e.g., --file).
⚠️ Note: Behavior varies between systems (GNU vs. BSD).

Example: Parse --file <file> and --verbose

#!/bin/bash

# Parse options with getopt (GNU version)
args=$(getopt -o f:v --long file:,verbose -- "$@") || exit 1
eval set -- "$args"

while true; do
  case "$1" in
    -f|--file)
      echo "File: $2"
      shift 2
      ;;
    -v|--verbose)
      echo "Verbose mode enabled"
      shift
      ;;
    --)
      shift
      break
      ;;
    *)
      echo "Internal error"
      exit 1
      ;;
  esac
done

echo "Remaining arguments: $@"

Usage:

./script.sh --file data.txt --verbose remaining_arg

Key Points:

  • -o f:v: Short options (-f with argument, -v as flag).
  • --long file:,verbose: Long options (same as short options).
  • eval set -- "$args": Reorganizes arguments for processing.
  • --: Separates options from non-option arguments.

4. Handling Non-Option Arguments

After parsing options, access remaining arguments with $@:

#!/bin/bash
while getopts ":a" opt; do
  # ... process options ...
done
shift $((OPTIND -1))

for arg in "$@"; do
  echo "Non-option argument: $arg"
done

5. Best Practices

  1. Error Handling:
  • Use getopts‘s \? and : cases to handle invalid/missing arguments.
  1. Portability:
  • Prefer getopts (POSIX-compliant) for short options.
  • Use getopt cautiously (check for GNU/BSD differences).
  1. Help Messages:
  • Include a usage() function for clarity:
    bash usage() { echo "Usage: $0 [-a] [-f file] [args...]" exit 1 }

Summary

MethodUse CaseProsCons
PositionalSimple scripts with fixed argsNo setup requiredInflexible for options
getoptsShort options (-a, -f val)Built-in, POSIX-compliantNo long option support
getoptLong options (--file)Supports long optionsNot POSIX; system-dependent

Example Workflow

  1. Define Options:
   while getopts ":ab:c" opt; do
     case $opt in
       a) echo "Flag -a";;
       b) echo "Option -b with $OPTARG";;
       c) echo "Flag -c";;
       \?) echo "Invalid option"; exit 1;;
     esac
   done
  1. Process Remaining Args:
   shift $((OPTIND -1))
   echo "Remaining args: $@"

Use these techniques to build robust CLI tools in Bash!

Leave a Reply

Your email address will not be published. Required fields are marked *