Fxb*_*aez 9 bash regular-expression
我试图在 bash 的 if 语句中再次匹配字符串和正则表达式。代码如下:
var='big'
If [[ $var =~ ^b\S+[a-z]$ ]]; then
echo $var
else
echo 'none'
fi
Run Code Online (Sandbox Code Playgroud)
匹配应该是一个以“b”开头的字符串,后跟一个或多个非空白字符并以字母 az 结尾。我可以匹配字符串的开头和结尾,但 \S 无法匹配非空白字符。在此先感谢您的帮助。
小智 16
在非 GNU 系统中,以下解释了\S
失败的原因:
它\S
是 PCRE(Perl 兼容正则表达式)的一部分。它不是shell 中使用的BRE(基本正则表达式)或ERE(扩展正则表达式)的一部分。
=~
双括号测试中的 bash 运算符[[
使用 ERE。
ERE 中唯一具有特殊含义的字符(与任何普通字符相反)是.[\()*+?{|^$
. 没有S
那么特别。您需要从更基本的元素构建正则表达式:
regex='^b[^[:space:]]+[a-z]$'
Run Code Online (Sandbox Code Playgroud)
其中括号表达式[^[:space:]]
等效于\S
PCRE 表达式:
默认\s
字符现在是 HT (9)、LF (10)、VT (11)、FF (12)、CR (13) 和空格 (32)。
测试将是:
var='big' regex='^b[^[:space:]]+[a-z]$'
[[ $var =~ $regex ]] && echo "$var" || echo 'none'
Run Code Online (Sandbox Code Playgroud)
但是,bißß
例如上面的代码将匹配。因为该范围[a-z]
将包括其他字符,而不是abcdefghijklmnopqrstuvwxyz
所选区域设置为 (UNICODE)。为避免此类问题,请使用:
var='bißß' regex='^b[^[:space:]]+[a-z]$'
( LC_ALL=C;
[[ $var =~ $regex ]]; echo "$var" || echo 'none'
)
Run Code Online (Sandbox Code Playgroud)
请注意,代码只会匹配列表abcdefghijklmnopqrstuvwxyz
中的字符:在最后一个字符位置,但仍会匹配中间的许多其他字符:例如bég
.
尽管如此,这种使用LC_ALL=C
将影响其他正则表达式范围:[[:space:]]
将仅匹配 C 语言环境的空格。
为了解决所有问题,我们需要将每个正则表达式分开:
reg1=[[:space:]] reg2='^b.*[a-z]$' out=none
if [[ $var =~ $reg1 ]] ; then out=none
elif ( LC_ALL=C; [[ $var =~ $reg2 ]] ); then out="$var"
fi
printf '%6.8s\t|' "$out"
Run Code Online (Sandbox Code Playgroud)
内容如下:
b
并以a-z
(在 C 语言环境中)结尾。请注意,这两个测试都是在正范围内完成的(与“非”范围相反)。原因是否定几个字符会打开更多可能的匹配项。UNICODE v8 已经分配了 120,737 个字符。如果范围否定 17 个字符,则它接受 120720 个其他可能的字符,其中可能包括许多不可打印的控制字符。
限制中间字符可以具有的字符范围应该是一个好主意(是的,那些不会是空格,但可以是其他任何字符)。
[[ $var =~ ^b[^[:space:]]+[abcdefghijklmnopqrstuvwxyz]$ ]]
Run Code Online (Sandbox Code Playgroud)
什么[a-z]
匹配取决于语言环境,一般是不(仅)一个abcdefghijklmnopqrstuvwxyz
。
perl
的\S
(水平和垂直空间)现在也被其他一些正则表达式引擎识别[^[:space:]]
在 POSIX 和 bash 的 ERE 中。
bash
使用系统的 regexp 库来匹配这些正则表达式,但即使在正则表达式具有\S
运算符的系统(如最近的 GNU 系统)上,这也不起作用,因为:
[[ x = \S ]]
Run Code Online (Sandbox Code Playgroud)
bash
电话regcomp("S")
和:
[[ x = '\S' ]]
Run Code Online (Sandbox Code Playgroud)
bash
调用regcomp("\\S")
(两个反斜杠)。
但是,对于 bash-3.1 或者如果您打开 bash-3.1 兼容性shopt -s compat31
,则:
[[ x = '\S' ]]
Run Code Online (Sandbox Code Playgroud)
将在 ERE 支持的系统上工作(将匹配非空格字符)\S
。
$ bash -c "[[ x =~ '\S' ]]" || echo no
no
$ bash -O compat31 -c "[[ x =~ '\S' ]]" && echo yes
yes
Run Code Online (Sandbox Code Playgroud)
另一种选择是将正则表达式放在一个变量中:
$ a='\S' bash -c '[[ x =~ $a ]]' && echo yes
yes
Run Code Online (Sandbox Code Playgroud)
同样,这仅适用于\S
在其正则表达式中支持类似 perl 的系统。
与该bash
特定代码等效的 POSIX将是:
if expr " $var" : \
' b[^[:space:]]\{1,\}[abcdefghijklmnopqrstuvwxyz]$' \
> /dev/null; then
printf '%s\n' "$var"
else
echo none
fi
Run Code Online (Sandbox Code Playgroud)
或者:
case $var in
([!b]* | *[!abcdefghijklmnopqrstuvwxyz] | *[[:space:]]* | "" | ? | ??)
echo none;;
(*) printf '%s\n' "$var"
esac
Run Code Online (Sandbox Code Playgroud)