Command-line scripts are easier to reuse when named options replace a fragile positional-only interface. The Zsh getopts builtin reads short options one at a time while leaving the remaining arguments available to the rest of the script.
Each successful call to getopts writes an option letter to the loop variable, stores its value in OPTARG, and advances OPTIND to the next unparsed argument. A colon after an option letter means that option requires a value, so r: accepts both -r eu-west-1 and -reu-west-1.
Silent mode keeps option errors under the script's control instead of mixing builtin diagnostics with its interface. The finished parser accepts -n for dry-run mode, -r for a region override, and an environment name after the options; a leading colon in :nr: routes missing values and unknown options to explicit error branches.
Related: How to use conditionals in Zsh
Related: How to use a case statement in Zsh
Related: How to debug a Zsh script
Related: Parse command-line options in Bash with getopts
Steps to use getopts in Zsh:
- Create deploy-options.zsh with its interpreter, local emulation, and default option values.
- deploy-options.zsh
#!/usr/bin/env zsh emulate -L zsh setopt err_exit no_unset region="us-east-1" dry_run=0
emulate -L zsh gives the script local Zsh option settings, while no_unset stops accidental reads of undefined parameters.
- Append the recognized-option loop after the default values.
while getopts ":nr:" opt; do case $opt in n) dry_run=1 ;; r) region=$OPTARG ;; esac doneEach successful call to getopts supplies one option letter. The -n branch changes a flag, and the -r branch reads its required value from OPTARG.
- Insert the custom error branches before the esac line.
:) print -u2 -- "missing value for -$OPTARG" exit 2 ;; \?) print -u2 -- "unknown option: -$OPTARG" exit 2 ;;The leading colon in :nr: sets the loop variable to : for a missing value and ? for an unknown option. In both cases, OPTARG contains the affected option letter.
- Append the remaining-argument shift and usage guard after the option loop.
shift $(( OPTIND - 1 )) environment=${1-} if [[ -z $environment ]]; then print -u2 -- 'usage: deploy-options.zsh [-n] [-r region] environment' exit 2 fiOPTIND points to the first argument that getopts did not consume. After the shift, $1 is the environment name rather than an option or its value.
- Append the parsed values after the usage guard.
print -r -- "environment=$environment" print -r -- "region=$region" print -r -- "dry_run=$dry_run"
- Compare deploy-options.zsh with the completed parser.
- deploy-options.zsh
#!/usr/bin/env zsh emulate -L zsh setopt err_exit no_unset region="us-east-1" dry_run=0 while getopts ":nr:" opt; do case $opt in n) dry_run=1 ;; r) region=$OPTARG ;; :) print -u2 -- "missing value for -$OPTARG" exit 2 ;; \?) print -u2 -- "unknown option: -$OPTARG" exit 2 ;; esac done shift $(( OPTIND - 1 )) environment=${1-} if [[ -z $environment ]]; then print -u2 -- 'usage: deploy-options.zsh [-n] [-r region] environment' exit 2 fi print -r -- "environment=$environment" print -r -- "region=$region" print -r -- "dry_run=$dry_run"
- Check deploy-options.zsh for Zsh syntax errors.
$ zsh -n deploy-options.zsh
No output means Zsh parsed the file without finding a syntax error.
- Run the parser with both options before the remaining environment argument.
$ zsh deploy-options.zsh -n -r eu-west-1 staging environment=staging region=eu-west-1 dry_run=1
- Trigger the missing-value branch for the region option.
$ zsh deploy-options.zsh -r missing value for -r
- Trigger the unknown-option branch with an unsupported letter.
$ zsh deploy-options.zsh -x staging unknown option: -x
- Rerun the parser with both valid options and the remaining environment argument.
$ zsh deploy-options.zsh -n -r eu-west-1 staging environment=staging region=eu-west-1 dry_run=1
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.