← 中文资源

简体中文版本

Getopt 长短选项解析

用 getopt 解析长短选项:定义串声明参数形态、eval 重排参数序、循环消费标志与值、位置参数最后校验必填。

阅读英文原文

示例说明

手写 while case 解析参数会踩遍陷阱:–output=value 形态、选项后参数、– 分隔符、缩写选项。getopt 把这些一次处理:定义串的冒号声明参数归属,重排后的参数流保证标志先于位置参数整齐排列,eval set 把重排结果装回位置参数。校验逻辑随后就简单——数字格式、必填位置参数逐个断言。

技术要点

  • 定义串的冒号声明参数归属
  • 重排保证标志先于位置参数
  • – 分隔符正确终止选项解析

代码解读

解析循环按模式分支消费:无参标志 shift 一步、带参标志 shift 两步、– 是选项流终点;超时值用正则断言数字防注入奇怪值。循环结束后 $@ 只剩位置参数,数量校验与逐个存在性检查兜底。readonly 在解析完成后固化配置。

使用建议

macOS 自带的是 BSD getopt,需要 brew 的 GNU 版本或换 getopts 内建(无长选项)。选项默认值集中声明在解析前。usage 文本与定义串同步维护。

代码示例

#!/usr/bin/env bash
set -euo pipefail

# 选项定义:短串加长定义,冒号表示需要参数
readonly SHORT="vo:t:"
readonly LONG="verbose,output:,timeout:"

PARSED=$(getopt --alternative --options "${SHORT}" \
  --longoptions "${LONG}" --name "$0" -- "$")
eval set -- "${PARSED}"

VERBOSE=false
OUTPUT="./out"
TIMEOUT=30

while true; do
  case "$1" in
    -v | --verbose)  VERBOSE=true; shift ;;
    -o | --output)   OUTPUT="$2"; shift 2 ;;
    -t | --timeout)
      [[ "$2" =~ ^[0-9]+$ ]] || { echo "超时须为数字: $2" >&2; exit 2; }
      TIMEOUT="$2"; shift 2 ;;
    --) shift; break ;;
    *) echo "未知参数: $1" >&2; exit 2 ;;
  esac
done

[[ $# -ge 1 ]] || { echo "用法: $0 [-v] [-o 输出] [-t 超时] <输入...>" >&2; exit 2; }

readonly TIMEOUT
readonly OUTPUT

echo "verbose=${VERBOSE} output=${OUTPUT} timeout=${TIMEOUT}"
for input in "$@"; do
  [[ -f "$input" ]] || { echo "输入不存在: ${input}" >&2; exit 1; }
  echo "处理 ${input} -> ${OUTPUT}"
done