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

Bash : Parse options after arguments with 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 "" in
        -o|--option)
            shift
            OPTION=
            ;;
        --)
            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  in
        -o|--option) option="";;
        -h|--help  ) echo "$help"; exit 0;;
                  *) echo "unknown option: "; exit 1;;
    esac
}

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

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

在多年的 bash 编程中,我发现摆脱脑海中认为函数应该看起来像 f(x,y) 的骨头很有用,尤其是自从 bash 需要 clumsy/inefficient 代码来处理命令行参数。

选项参数通常有默认值,可以更容易地作为环境变量传递,其范围仅限于被调用的脚本,并保存必须提供的参数。

将此应用于您的示例,脚本如下所示:

OPTION=${OPTION:="fee"}
echo "option: $OPTION"
echo "remaining args are: $*"

并且会被调用:

OPTION="foo" ./options.sh arg1 arg2