我有一串短选项和选项,我想将其分成短选项字符串和长选项字符串。
opts="-p,--plong,--pext"
我的想法是使用 grep,它对于短选项确实有问题。
opts="-p,--plong,--pext"
short_opts=$(echo "$opts" | grep -o '\s*-\w*')
long_opts=$(echo "$opts" | grep -o '\s*--\w*')
echo
echo "short_opts: $short_opts"
echo "long_opts: $long_opts"
答案1
在 zsh 而不是 bash 中,你可以这样做:
opts="-p,--plong,--pext"
# split on ,s into an array
opts=( ${(s[,])opts} )
short_opts=( ${opts:#--*} )
long_opts=( ${(M)opts:#--*} )
然后,你得到两个数组:
$ typeset -p short_opts long_opts
typeset -a short_opts=( -p )
typeset -a long_opts=( --plong --pext )
要进行更严格的匹配,例如仅允许短选项后跟-
一个除 之外的任意一个字符-
,以及长选项--
后跟一个或多个除 之外的字符=
:
set -o extendedglob
short_opts=( ${(M)opts:#-[^-]} )
long_opts=( ${(M)opts:#--[^=]##} )
bash 没有拆分运算符(如s
上面 zsh 的参数扩展标志),但它在从 Bourne shell 继承的未加引号的扩展上执行臭名昭著的 split+glob。所以你可以用它来进行分割:
IFS=, # split on ,
set -o noglob
opts=( $opts )
它没有像 zsh${array:#pattern}
操作符那样的数组过滤操作符,但它有 ksh93 的${array[@]/pattern/replacement}
数组成员编辑操作符,并且不加引号的扩展会删除空元素,所以你可以这样做(假设noglob
仍然打开并且$IFS
为空或仍然只包含,
):
short_options=( ${opts[@]/#--*} )
long_options=( ${opts[@]/#-[!-]*} )
#
将模式锚定在开始处。%
会锚定在末尾,但与 zsh 相反,bash 不支持在开头和结尾锚定,因此您无法将元素作为一个整体进行匹配。case
如果您需要进行更严格的匹配,您始终可以循环所有元素并用于匹配:
short_opts=() long_opts=()
shopt -s extglob
for opt in "${opts[@]}"; do
case $opt in
( -[^-] ) short_opts+=( "$opt" );;
( --+([^=]) ) long_opts+=( "$opt" );;
esac
done
与 ksh 一样,bash 将含义$IFS
从S
分隔符更改为分隔符/终止符,这意味着a,,b,
将被拆分为a
,空字符串并且b
没有额外的空字符串。如果所有元素都是选项,这里就不是问题
答案2
我已经这样做了
opts="-p,--plong,--pext"
for opt in ${opts//,/ }; do
if [[ "$opt" == --* ]]; then
long_opts="$long_opts $opt"
elif [[ "$opt" == -* ]]; then
short_opts="$short_opts $opt"
fi
done
echo
echo "short_opts: $short_opts"
echo "long_opts: $long_opts"