我正在创建一个涉及解析参数的bash脚本。用法是:
$ ./my_script.sh -a ARG_1 -b ARG_2 [-c LIST_OF_ARGS...]
使用getopts
我可以解析-a
和-b
并获取各自的值ARG_1
和ARG_2
。当且仅当用户将-c
作为最后一个参数时,我才能获得-c
并创建一个包含LIST_OF_ARGS...
中所有值的列表。
但我不想强迫用户插入-c
作为最后一个标志。例如,如果可以通过这种方式调用脚本,那就太棒了:
$ ./my_script.sh -b ARG_2 -c V1 V2 V3 -a ARG_1
这是我目前的代码:
while getopts a:b:c opt
do
case $opt in
a)
A_FLAG=$OPTARG
;;
b)
B_FLAG=$OPTARG
;;
c)
# Handle values as regular expressions
args=("$@")
C_LIST=()
for (( i=$OPTIND-1 ; i <= $#-1 ; i++ ))
do
C_LIST=("${C_LIST[@]}" ${args[$i]})
done
;;
?)
usage
;;
esac
done
答案 0 :(得分:1)
在我的系统上,我没有/usr/share/doc/util-linux/examples/getopt-parse.bash
个文件。它将getopt
的结果放入变量中,并将位置参数设置为该变量。然后使用与您类似的switch
,但在找到时使用shift
删除参数。
您可以执行类似操作,但是对于-c
选项,请使用shift
,直到您获得选项或用完参数。
或者它可能足以让您使用当前的解决方案,但请记住在循环后设置 OPTIND
变量。
答案 1 :(得分:1)
您需要将-c
标志的检测与与之关联的处理分开。例如,像:
while getopts a:b:c opt
do
case $opt in
a)
A_FLAG=$OPTARG
;;
b)
B_FLAG=$OPTARG
;;
c)
C_FLAG=1
;;
?)
usage
;;
esac
done
# discard all of our options.
shift `expr $OPTIND - 1`
if [ "$C_FLAG" = 1 ]; then
# Handle values as regular expressions
args=("$@")
C_LIST=()
for (( i=0 ; i <= $#-1 ; i++ ))
do
C_LIST=("${C_LIST[@]}" ${args[$i]})
done
fi
在处理完所有命令行选项之前,此脚本不会收集所有非选项参数。
答案 2 :(得分:1)
这是一个问题:为什么要使用-c选项?
如果完整用法涉及值列表,为什么不只是没有-c选项并且只允许-a和-b选项,而其余的是./myscript.sh -a ARG_1 -b ARG_2 [argument ...]
中的常规args,其中任何参数都是可选的(比如-c选项及其参数在您的用法示例中?
然后你的问题变成“我如何穿插程序选项和参数”,我会回答:“你不应该这样做,但无论如何要实现这一点,自己解析命令行; getopts
赢了不按照你想要的方式工作。“
当然,解析是很难的方法。另一种可能性是将-c之后的值添加到列表中,只要您没有遇到其他选项或选项的结尾:
C_LIST=()
while getopts a:b:c: opt; do
#Skipping code...
c)
C_LIST+="$OPTARG"
shift $(expr $OPTIND - 1)
while [ -n "$1" ] && [ $(printf "%s" "$1" | grep -- '^[^-]') ]; do
C_LIST+="$1"
shift
done
OPTIND=1
;;
模仿getopts的行为:即使OPTARG以' - '字符开头,它仍然保留,但在OPTARG之后,任何以' - '字符开头的字符串可能只是一个无效的选项,如-n。我使用printf而不是echo,因为某些版本的echo(例如bash内置的echo)有一个-e选项,可能允许或不允许循环继续,这是不希望的。 grep表达式应该阻止这个,但是谁知道这个版本的echo是否允许-e'hello',这会导致grep成功,因为它看到“你好”?虽然可能没必要,为什么要冒险?
就个人而言,如果可以,我会避免这种行为,但我也不明白为什么你首先要求这种行为。如果我要推荐任何东西,我建议采用比任何其他可能的实施选择更常见的/path/to/script -a ARG_1 -b ARG_2 [argument ...]
样式。