我试图将字符串与 bash 上 if 语句内的正则表达式进行匹配。代码如下:
var='big'
If [[ $var =~ ^b\S+[a-z]$ ]]; then
echo $var
else
echo 'none'
fi
匹配应该是一个以“b”开头,后跟一个或多个非空白字符并以字母 az 结尾的字符串。我可以匹配字符串的开头和结尾,但 \S 无法匹配非空白字符。先谢谢您的帮助。
答案1
在非 GNU 系统中,以下内容解释了\S
失败的原因:
它\S
是 PCRE(Perl 兼容正则表达式)的一部分。它不属于BRE(基本正则表达式)或者ERE(扩展正则表达式)用于贝壳。
=~
双括号测试中的bash 运算符[[
使用 ERE。
在 ERE 中唯一具有特殊含义的字符(与任何普通字符相反)是.[\()*+?{|^$
。没有S
那么特别。您需要从更基本的元素构建正则表达式:
regex='^b[^[:space:]]+[a-z]$'
哪里的括号表达式[^[: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'
但是,上面的代码将匹配bißß
例如。因为范围将包含除所选语言环境 (UNICODE)[a-z]
之外的其他字符。abcdefghijklmnopqrstuvwxyz
为了避免此类问题,请使用:
var='bißß' regex='^b[^[:space:]]+[a-z]$'
( LC_ALL=C;
[[ $var =~ $regex ]]; echo "$var" || echo 'none'
)
请注意,代码将仅匹配列表中的字符: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"
内容如下:
- 如果输入 (var) 没有空格(在当前语言环境中)则
- 检查它是否以 a 开头并以(在 C 语言环境中)
b
结尾。a-z
请注意,这两个测试都是在正范围(而不是“非”范围)上完成的。原因是否定几个字符会产生更多可能的匹配。 UNICODE v8 已分配 120,737 个字符。如果某个范围否定 17 个字符,则它接受 120720 个其他可能的字符,其中可能包括许多不可打印的控制字符。
限制中间字符可以具有的字符范围应该是一个好主意(是的,这些字符不会是空格,但可能是其他任何字符)。
答案2
[[ $var =~ ^b[^[:space:]]+[abcdefghijklmnopqrstuvwxyz]$ ]]
匹配的内容[a-z]
取决于区域设置,通常是不是(仅)其中之一abcdefghijklmnopqrstuvwxyz
。
perl
的\S
(水平和垂直空格)现在也被其他一些正则表达式引擎识别,位于[^[:space:]]
POSIX 和 bash 的 ERE 中。
bash
使用系统的正则表达式库来匹配这些正则表达式,但即使在正则表达式具有运算\S
符的系统(例如最近的 GNU 系统)上,这也不起作用,因为在:
[[ x = \S ]]
bash
调用regcomp("S")
并与:
[[ x = '\S' ]]
bash
调用regcomp("\\S")
(两个反斜杠)。
但是,使用 bash-3.1 或者如果您使用 启用 bash-3.1 兼容性shopt -s compat31
,则:
[[ x = '\S' ]]
将在 ERE 支持的系统上工作(将匹配非空格字符)\S
。
$ bash -c "[[ x =~ '\S' ]]" || echo no
no
$ bash -O compat31 -c "[[ x =~ '\S' ]]" && echo yes
yes
另一种选择是将正则表达式放入变量中:
$ a='\S' bash -c '[[ x =~ $a ]]' && echo yes
yes
\S
同样,这只适用于在正则表达式中支持类似 perl 的系统。
与该特定代码等效的 POSIXbash
是:
if expr " $var" : \
' b[^[:space:]]\{1,\}[abcdefghijklmnopqrstuvwxyz]$' \
> /dev/null; then
printf '%s\n' "$var"
else
echo none
fi
或者:
case $var in
([!b]* | *[!abcdefghijklmnopqrstuvwxyz] | *[[:space:]]* | "" | ? | ??)
echo none;;
(*) printf '%s\n' "$var"
esac
答案3
概括
# match any non-whitespace char--works in bash and `grep` too
[^\r\n\t\f\v ]
细节
匹配(任何非空白字符)显然在or或类似的\S
正则表达式中不起作用。因此,不要使用它来匹配一个或多个出现的任何非空白字符:bash
grep
# INSTEAD OF THESE (which do NOT work in bash or `grep`)
# match one or more non-whitespace chars
\S+
# or (same thing)
[\S]+
...用这个:
如何匹配bash
and中的所有非空白字符grep
# match one or more non-whitespace chars (DOES work in bash and `grep`!)
[^\r\n\t\f\v ]+
我从那里学到了这一点https://regex101.com/。点击这里:https://regex101.com/r/kM041K/1,在屏幕右侧的“说明”部分下,您将看到:
\S
匹配任何非空白字符(相当于[^\r\n\t\f\v ]
)
因此,如果对任何正则表达式有疑问,请访问该网站并查看其内容。