如何将长选项传递给 Bash 脚本?

3
./script.sh -abc hello

我该如何编写脚本以使用“-abc”作为选项,且将“hello”作为该选项的值?
我应该能够将此值传递给脚本中的所有函数。假设我有两个函数:XY

你在问什么?Bash没有内置支持处理长选项的功能 - getoptgetopts都只能处理单字符选项。你需要通过循环"$@"来自己解析它。 - Mark Reed
在Shell编程中没有办法实现上述功能吗? - skyrocker
@MarkReed getopt(1) 支持长选项,但要安全使用它需要知道你是否有 util-linux 版本(或者它不支持带空格的选项)。 - Etan Reisner
1
你目前如何处理脚本参数?你在这样做吗?Bash FAQ 35提供了一些很好的建议来处理脚本参数。 - Etan Reisner
请参考以下链接https://dev59.com/h3RC5IYBdhLWcg3wG9bp,了解如何在Bash shell脚本中使用getopts获取长命令行选项和短命令行选项。 - drizzt
3个回答

2

在您的脚本中使用以下代码:

[[ $1 == -abc ]] && value="$2" || echo invalid option

如果您不希望在选择错误或没有选项时打印任何消息,则省略|| echo ...部分,value将为空。
如果您想使第二个参数成为必填项,则:
[[ $1 == -abc ]] && [[ $2 != "" ]] && value="$2" || echo invalid option

使用if else循环可以完全控制这个过程:

if [[ $1 == -abc ]]; then
#if first option is valid then do something here
if [[ $2 != "" ]]; then
 value="$2"
 else
 #if second option is not given then do something here
 echo invalid option
 fi
 else
 echo invalid option
 #if first option is invalid then do something here
 fi

如果您希望第一个参数也是必需的,则将第一条if语句行更改为:
if [[ $1 == -abc && $1 != "" ]]; then

如果您想传递任意数量的参数并处理它们,则可以使用以下代码:
#!/bin/bash
opts=( "$@" )
#if no argument is passed this for loop will be skipped
for ((i=0;i<$#;i++));do
case "${opts[$i]}" in
   -abc)

    # "${opts[$((i+1))]}" is the immediately follwing option
    [[ "${opts[$((i+1))]}" != "" ]] &&
    value="${opts[$((i+1))]}"
    echo "$value"
    ((i++))
    #skips the nex adjacent argument as it is already taken

    ;;

   -h)
   #dummy help option
   echo "Options are [-abc value], -h"

    ;;

   *)
   #other unknown options
   echo invalid option
    break

    ;;
esac
done

这是一个处理多个参数且仅有两个选项可用的示例 -abc value-h

1
这很有帮助,但缺乏足够的上下文来成为一个真正完整的答案。解释如何将其适应更大的参数解析上下文将是有帮助的。 - Etan Reisner
谢谢您的回答,但基本上我想验证这个“-abc”是否应该始终传递一个值...我猜它会在if-else循环中,但不确定该如何做。 - skyrocker
完全同意 @EtanReisner 的观点。该代码检查了一组非常严格的参数设置和位置。通常,当解析命令行时,选项(及其参数)可以按任何顺序出现,只要它们出现在非选项之前即可。 - ctt
OP没有说明是否有多个选项。 - Jahid
@EtanReisner,添加了多个选项的代码,请让我知道您是否有任何建议。 - Jahid

1

bash 没有用于处理长参数的内置命令。为了在shell脚本中解析长选项,您需要自己迭代参数列表。

这是一种方法:

#!/bin/sh

is_option_arg () {
        case $1 in
                -*)
                        return 1
                        ;;
                *)
                        return 0
                        ;;
        esac
}

usage () {
        echo "$(basename "$0") -abc ARG -def ARG -verbose"
}



OPT_ABC=
OPT_DEF=
OPT_VERBOSE=false

while [ "$#" -gt 0 ]; do
        case $1 in
                -abc)
                        shift
                        { [ "$#" -ne 0 ] && is_option_arg "$1"; } || { usage >&2; exit 1; }
                        OPT_ABC=$1
                        ;;
                -def)
                        shift
                        { [ "$#" -ne 0 ] && is_option_arg "$1"; } || { usage >&2; exit 1; }
                        OPT_DEF=$1
                        ;;
                -verbose)
                        OPT_VERBOSE=true
                        ;;
                *)
                        break
                        ;;
        esac

        shift
done

echo "OPT_ABC=$OPT_ABC"
echo "OPT_DEF=$OPT_DEF"
echo "OPT_VERBOSE=$OPT_VERBOSE"

if [ "$#" -gt 0 ]; then
        echo "Remaining args:"

        for arg in "$@"; do
                echo "$arg"
        done
fi

1

你几乎必须手动实现它。以下是一种方法:

abc=
while [[ "$1" == -* ]]; do
  opt=$1
  shift
  case "$opt" in
   -abc) 
    if (( ! $# )); then
      echo >&2 "$0: option $opt requires an argument."
      exit 1
    fi
    abc="$1"
    shift
    ;; 
   *) 
    echo >&2 "$0: unrecognized option $opt."
    exit 2
    ;;
  esac
done
echo "abc is '$abc', remaining args: $*"

以上内容的一些示例运行:
(0)$ ./script.sh
abc is '', remaining args:
(0)$ ./script.sh hello
abc is '', remaining args: hello
(0)$ ./script.sh -abc hello
abc is 'hello', remaining args:
(0)$ ./script.sh -abc hello there
abc is 'hello', remaining args: there
(0)$ ./script.sh -abc
./script.sh: option -abc requires an argument.
(1)$ ./script.sh -bcd
./script.sh: unrecognized option -bcd.
(2)$

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接