任何非空白正则表达式

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:]] 等效于\SPCRE 表达式

默认\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)

内容如下:

  • 如果输入 (var) 没有空格(在当前语言环境中),则
  • 检查它是否以 a 开头b并以a-z(在 C 语言环境中)结尾。

请注意,这两个测试都是在正范围内完成的(与“非”范围相反)。原因是否定几个字符会打开更多可能的匹配项。UNICODE v8 已经分配了 120,737 个字符。如果范围否定 17 个字符,则它接受 120720 个其他可能的字符,其中可能包括许多不可打印的控制字符。

限制中间字符可以具有的字符范围应该是一个好主意(是的,那些不会是空格,但可以是其他任何字符)。


Sté*_*las 6

[[ $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)