Bash:使用 getopts 解析参数后的选项

问题描述

在请求一些参数 (arg) 和选项 (-a) 的脚本中,我想让脚本用户可以将选项放在命令行中他想要的位置。

这是我的代码

while getopts "a" opt; do
  echo "$opt"
done
shift $((OPTIND-1))

echo "all_end : $*"

有了这个命令,我就有了预期的行为:

./test.sh -a arg
a
all_end : arg

我想用这个命令得到相同的结果:

./test.sh arg -a
all_end : arg -a

解决方法

getopt 命令(util-linux 包的一部分,与 getopts 不同)将执行您想要的操作。 bash faq 对使用它有一些意见,但老实说,现在大多数系统都将拥有 getopt 的现代版本。

考虑以下示例:

#!/bin/sh

options=$(getopt -o o: --long option: -- "$@")
eval set -- "$options"

while :; do
    case "$1" in
        -o|--option)
            shift
            OPTION=$1
            ;;
        --)
            shift
            break
            ;;
    esac

    shift
done

echo "got option: $OPTION"
echo "remaining args are: $@"

我们可以这样称呼它:

$ ./options.sh -o foo arg1 arg2
got option: foo
remaining args are: arg1 arg2

或者像这样:

$ ./options.sh  arg1 arg2 -o foo
got option: foo
remaining args are: arg1 arg2
,

您仍然可以通过查看每个参数来解析参数

#!/bin/bash

for i in "$@"
do
case $i in
    -a)
    ARG1="set"
    shift
    ;;
    *)
    # the rest (not -a)
    ARGS="${ARGS} $i"
    ;;
esac
done

if [ -z "$ARG1" ]; then
  echo "You haven't passed -a"
else
  echo "You have passed -a"
fi

echo "You have also passed: ${ARGS}"

然后你会得到:

> ./script.sh arg -a
You have passed -a
You have also passed:  arg
> ./script.sh -a arg
You have passed -a
You have also passed:  arg
> ./script.sh -a
You have passed -a
You have also passed:
> ./script.sh arg
You haven't passed -a
You have also passed:  arg
,

考虑这种方法

#!/bin/bash
    
opt(){
    case $1 in
        -o|--option) option="$2";;
        -h|--help  ) echo "$help"; exit 0;;
                  *) echo "unknown option: $1"; exit 1;;
    esac
}

while [[ $@ ]]; do
    case $1 in
      arg1) var1=$1 ;;
      arg2) var2=$1 ;;
        -*) opt "$@"; shift;;
         *) echo "unknown option: $1"; exit 1;;
    esac
    shift
done

echo args: $var1 $var2
echo opts: $option