Bash getopts:识别否定选项(-x- 或 +x)?
Bash getopts: recognizing negative options (-x- or +x)?
(类似于 this,但在 bash 中。)
我有一个现有的 bash 脚本,它使用内置的 getopts 来识别 -s
(仅标记 - 无参数)。我发现我每次都使用该选项,所以我想将其设为默认值 ,除非在命令行中指定 -s-
或 +s
。不过,虽然ksh getopts
can handle +s
, I can't find that capability in the bash getopts
manual。
我目前的解决方法是:
- 使用
s:
所以我可以通过$OPTARG
="-"
识别-s-
;或
- 用不同的选项替换
-s
,例如 -d
(对于 "don't")。
但是,#1 的问题是如果我不小心指定了 -s
,它会吞下下一个参数,#2 的问题是它使用了与我已经拥有的不同的开关字母记忆。我希望可能有一种直接的方法来解析 bash 中的 -s-
或 +s
。
- util-linux getopt(1) 似乎也没有
+s
。它可以处理可选参数,因此可以接受 -s-
。但是,我以前没有使用过 getopt(1)
,所以希望能得到有关如何不搬起石头砸自己脚的指点。
- BashFAQ 035 说 "parse it yourself." 如果您已经编写了执行
+s
或 -s-
的例程,我很乐意看到它。
我当前的 arg-parsing 循环非常基础:
while getopts "nthps" opt ; do
case "$opt" in
<other cases cut>
(s) saw_s="yes"
;;
esac
done
shift $((OPTIND-1))
负标志序列 (+abcdef +g
) 与只有加号的正常序列 (-abcdef -g
) 不同。所以你可以简单地恢复 +
前缀的标志值。
第二种形式的负序就这么简单。只去掉最后一个字符(-
),并否定正常的标志值。
例子
以下脚本接受所有提到的格式,例如-ns -n -s -n- -ns- +ns +n +s
.
arglist='ns'
while (( $# )); do
arg=""
# Parse -abcdef- (negative form of -abcdef) options
if [ "${arg:0:1}" = '-' -a "${arg#${arg%?}}" = '-' ]; then
flag_val=no
arg="${arg%?}" # -abcdef- becomes -abcdef
elif [ "${arg:0:1}" = '+' ]; then
flag_val=no
arg="${arg/#+/-}"
else
flag_val=yes
fi
# OPTIND is the index of the next argument to be processed.
# We are going to parse "$arg" from the beginning, so we need
# to reset it to 1 before calling getopts.
OPTIND=1
while getopts "$arglist" opt "$arg"; do
case "$opt" in
s) saw_s="$flag_val" ;;
n) saw_n="$flag_val" ;;
esac
done
shift
done
# Set default values
: ${saw_s:=yes}
: ${saw_n:=no}
printf "saw_s='%s'\nsaw_n='%s'\n" "$saw_s" "$saw_n"
测试
$ ./pargs.sh
saw_s='yes'
saw_n='no'
$ ./pargs.sh -s
saw_s='yes'
saw_n='no'
$ ./pargs.sh +s
saw_s='no'
saw_n='no'
$ ./pargs.sh -s-
saw_s='no'
saw_n='no'
$ ./pargs.sh -s- +s -s
saw_s='yes'
saw_n='no'
$ ./pargs.sh -s +s
saw_s='no'
saw_n='no'
$ ./pargs.sh +s -s
saw_s='yes'
saw_n='no'
$ ./pargs.sh -s -s-
saw_s='no'
saw_n='no'
$ ./pargs.sh -sn
saw_s='yes'
saw_n='yes'
$ ./pargs.sh -sn -s-
saw_s='no'
saw_n='yes'
$ ./pargs.sh -sn +s
saw_s='no'
saw_n='yes'
$ ./pargs.sh +sn
saw_s='no'
saw_n='no'
$ ./pargs.sh -sn-
saw_s='no'
saw_n='no'
$ ./pargs.sh -sn- -n
saw_s='no'
saw_n='yes'
(类似于 this,但在 bash 中。)
我有一个现有的 bash 脚本,它使用内置的 getopts 来识别 -s
(仅标记 - 无参数)。我发现我每次都使用该选项,所以我想将其设为默认值 ,除非在命令行中指定 -s-
或 +s
。不过,虽然ksh getopts
can handle +s
, I can't find that capability in the bash getopts
manual。
我目前的解决方法是:
- 使用
s:
所以我可以通过$OPTARG
="-"
识别-s-
;或 - 用不同的选项替换
-s
,例如-d
(对于 "don't")。
但是,#1 的问题是如果我不小心指定了 -s
,它会吞下下一个参数,#2 的问题是它使用了与我已经拥有的不同的开关字母记忆。我希望可能有一种直接的方法来解析 bash 中的 -s-
或 +s
。
- util-linux getopt(1) 似乎也没有
+s
。它可以处理可选参数,因此可以接受-s-
。但是,我以前没有使用过getopt(1)
,所以希望能得到有关如何不搬起石头砸自己脚的指点。 - BashFAQ 035 说 "parse it yourself." 如果您已经编写了执行
+s
或-s-
的例程,我很乐意看到它。
我当前的 arg-parsing 循环非常基础:
while getopts "nthps" opt ; do
case "$opt" in
<other cases cut>
(s) saw_s="yes"
;;
esac
done
shift $((OPTIND-1))
负标志序列 (+abcdef +g
) 与只有加号的正常序列 (-abcdef -g
) 不同。所以你可以简单地恢复 +
前缀的标志值。
第二种形式的负序就这么简单。只去掉最后一个字符(-
),并否定正常的标志值。
例子
以下脚本接受所有提到的格式,例如-ns -n -s -n- -ns- +ns +n +s
.
arglist='ns'
while (( $# )); do
arg=""
# Parse -abcdef- (negative form of -abcdef) options
if [ "${arg:0:1}" = '-' -a "${arg#${arg%?}}" = '-' ]; then
flag_val=no
arg="${arg%?}" # -abcdef- becomes -abcdef
elif [ "${arg:0:1}" = '+' ]; then
flag_val=no
arg="${arg/#+/-}"
else
flag_val=yes
fi
# OPTIND is the index of the next argument to be processed.
# We are going to parse "$arg" from the beginning, so we need
# to reset it to 1 before calling getopts.
OPTIND=1
while getopts "$arglist" opt "$arg"; do
case "$opt" in
s) saw_s="$flag_val" ;;
n) saw_n="$flag_val" ;;
esac
done
shift
done
# Set default values
: ${saw_s:=yes}
: ${saw_n:=no}
printf "saw_s='%s'\nsaw_n='%s'\n" "$saw_s" "$saw_n"
测试
$ ./pargs.sh
saw_s='yes'
saw_n='no'
$ ./pargs.sh -s
saw_s='yes'
saw_n='no'
$ ./pargs.sh +s
saw_s='no'
saw_n='no'
$ ./pargs.sh -s-
saw_s='no'
saw_n='no'
$ ./pargs.sh -s- +s -s
saw_s='yes'
saw_n='no'
$ ./pargs.sh -s +s
saw_s='no'
saw_n='no'
$ ./pargs.sh +s -s
saw_s='yes'
saw_n='no'
$ ./pargs.sh -s -s-
saw_s='no'
saw_n='no'
$ ./pargs.sh -sn
saw_s='yes'
saw_n='yes'
$ ./pargs.sh -sn -s-
saw_s='no'
saw_n='yes'
$ ./pargs.sh -sn +s
saw_s='no'
saw_n='yes'
$ ./pargs.sh +sn
saw_s='no'
saw_n='no'
$ ./pargs.sh -sn-
saw_s='no'
saw_n='no'
$ ./pargs.sh -sn- -n
saw_s='no'
saw_n='yes'