Reading — step 1 of 7
Learn
~2 min readCommand Substitution and Exit Status
Robust shell scripts accept arguments. getopts is bash's POSIX-compliant tool for parsing short options. The Bash Reference Manual covers it; every production script uses it.
The basics
#!/bin/bash
verbose=0
file=""
while getopts "vf:" opt; do
case $opt in
v) verbose=1 ;;
f) file=$OPTARG ;;
*) echo "Usage: $0 [-v] [-f file]" >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1))
echo "verbose=$verbose file=$file remaining=$@"
Usage:
./script.sh -v -f config.txt extra1 extra2
# verbose=1 file=config.txt remaining=extra1 extra2
Key pieces:
getopts "vf:" opt— option string.vis a flag (no arg);f:requires an arg.$OPTARG— value of the option that requires an arg$OPTIND— index of the next argument; useshift $((OPTIND - 1))to consume processed options$@— remaining positional args after option parsing
Combining short flags
./script.sh -vf config.txt # -v and -f config.txt
Getopts handles this — -vf foo is the same as -v -f foo.
Required vs optional argument options
while getopts ":hv:f:o:" opt; do # leading colon = silent mode: getopts sets OPTARG on errors
case $opt in
h) show_help; exit 0 ;;
v) verbose=$OPTARG ;; # required arg
f) file=$OPTARG ;; # required arg
o) output=$OPTARG ;; # required arg
:) echo "option -$OPTARG needs an argument" >&2; exit 1 ;;
\?) echo "unknown option: -$OPTARG" >&2; exit 1 ;;
esac
done
Getopts only handles short options (-v, -f). For LONG options (--verbose, --file), use getopt (different program, GNU extension) or hand-parse.
Hand-parsing for long options
while [[ $# -gt 0 ]]; do
case "$1" in
--verbose|-v) verbose=1; shift ;;
--file|-f) file="$2"; shift 2 ;;
--output=*) output="${1#*=}"; shift ;;
--help|-h) show_help; exit 0 ;;
--) shift; break ;;
-*) echo "unknown option: $1" >&2; exit 1 ;;
*) break ;;
esac
done
More code than getopts but supports --long-options, --option=value, mixed positions.
Reading user input — read
For scripts that PROMPT:
read -r -p "Enter your name: " name
echo "Hello, $name"
read -r -s -p "Password: " password # silent (no echo)
echo # newline since silent suppressed it
read -r -t 5 -p "Quick! " answer # 5-second timeout
if [ -z "$answer" ]; then
echo "timeout"
fi
-r— don't interpret backslashes (almost always desired)-p "prompt"— display prompt-s— silent (passwords)-t SEC— timeout-n N— read exactly N chars
Common mistakes
- Forgetting
shift $((OPTIND - 1))— leftover arguments include the parsed options. - Not handling
\?— getopts sets opt to?for unknown options. Without a case, your script silently misbehaves. - Trying to use
getoptsfor long options — doesn't support them. Use GNUgetoptor hand-parse. readwithout-r— interprets backslashes. Almost always wrong; always use-r.- No usage / help — every script needs
-hor--helpshowing what flags it accepts.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…