我想编写一个全局模式来匹配以逗号分隔的数字。图案会是什么样子?
这里有些例子
5
5,8,13
已从以下内容开始,但存在一些问题,因为我没有得到匹配。
var="8,13,21"
echo "var: $var"
if [[ "$var" == ^*([[:digit:]])+(,+[[:digit:]])$ ]]; then
echo "match"
fi
答案1
bash 手册描述了[[ expression ]]
语法:
==
使用和运算符时!=
,运算符右侧的字符串被视为模式,并根据模式匹配下描述的规则进行匹配,就像extglob
启用了 shell 选项一样。
这里的 shell选项extglob
表示 ksh 风格的扩展 glob,即:
?(pattern-list)
Matches zero or one occurrence of the given patterns
*(pattern-list)
Matches zero or more occurrences of the given patterns
+(pattern-list)
Matches one or more occurrences of the given patterns
@(pattern-list)
Matches one of the given patterns
!(pattern-list)
Matches anything except one of the given patterns
我怀疑+[[:digit:]]
是试图匹配 1 个或多个数字 - 这需要是+([[:digit:]])
.所以逗号后跟 1 个或多个数字,所有零次或多次都是*(,+([[:digit:]])
,最后
+([[:digit:]])*(,+([[:digit:]]))
匹配 1 个或多个数字,后跟零个或多个逗号分隔的一个或多个数字以形成逗号分隔列表。
请注意,glob 表达式不使用^
和$
锚点 - 它们始终是整行,如果您想要部分匹配,则需要用*
通配符将表达式括起来。
1 这是自 bash 4.1 以来的新内容。在旧版本中,您需要显式地shopt -s extglob
让那些扩展的全局运算符在内部可用,就像在外部一样[[...]]
。
答案2
请注意,您使用的语法看起来像是通配符和正则表达式语法的混合。
如果你想使用 Bash 的 RegEx 匹配(如上所述在评论中),那么您需要使用=~
比较运算符。在这种情况下,测试构造的正确语法是
if [[ "$var" =~ ^([[:digit:]])+(,[[:digit:]]+)*$ ]]; then
...
请注意,这与您在几个方面展示的尝试不同:
- 在您当前的尝试中,
,+[[:digit:]]
将匹配“一个或多个逗号,后跟一位数字”。 - RegEx开头
*
的 似乎是杂散的 - 只要您不打算匹配文字*
,它要么是错误的(*
在 RegEx 中意味着“零个或多个前面的字符”,而不是“任何可能的字符组合”)或多余的(如果你想匹配$.*
,你也可以去掉锚并简单地声明([[:digit:]])+(,+[[:digit:]])$
)。
另一方面,如果您实际上想使用“扩展通配符”语法(在运算符[[ ... ]]
的构造中确实默认接受该语法==
),那么
^
锚点 (和)的使用$
是错误的 - 它们仅对正则表达式有效,而不是通配语法的一部分,即使是扩展形式也是如此。它们也不是必需的,因为默认情况下,全局模式适用于整个字符串。- 此外,每一个前面有“重复说明符”(例如
*
或+
)的项目需要放在括号中,因此语句中缺少一组括号+[[:digit:]]
。
所以在这种情况下,你的匹配 glob 需要看起来像
if [[ "$var" == +([[:digit:]])*(,+([[:digit:]])) ]]; then echo "match"; fi
答案3
为了完整起见,如果您想sh
在语句中使用标准通配符case
([[...]]
是 kshism)来做到这一点,您需要采取相反的方法:
case $var in
('' | *[!,0123456789]* | *, | ,* | *,,* ) echo WRONG;;
(*) echo RIGHT;;
esac
标准 glob 模式中没有 ERE 的等效项+
(与 zsh##
或 ksh相同)。+(...)
但是,您可以借助以下命令进行正则表达式匹配¶ awk
:
rematch() { awk -- 'BEGIN{exit(ARGV[1] !~ ARGV[2])}' "$@"; }
if rematch ",$var" '^(,[0123456789]+)+$'; then
echo RIGHT
else
echo WRONG
fi
1 在 中awk
,您会得到标准扩展正则表达式的一个变体,它也可以理解(或意味着理解,但并非全部以这种方式使用)ANSI C 转义序列,例如\n
, \t
, \b
(用于退格,而不是 perl 样式的单词边界)。