2010-02-27 170 views
58

我想知道在bash中if语句中使用正则表达式的一般规则吗?在bash中if条件中使用正则表达式

下面是一个例子

$ gg=svm-grid-ch 
$ if [[ $gg == *grid* ]] ; then echo $gg; fi 
svm-grid-ch 
$ if [[ $gg == ^....grid* ]] ; then echo $gg; fi 
$ if [[ $gg == ....grid* ]] ; then echo $gg; fi 
$ if [[ $gg == s...grid* ]] ; then echo $gg; fi 
$ 

为什么最后三个不匹配?

希望你能给出尽可能多的一般规则,而不仅仅是这个例子。

回答

91

当使用glob模式,问号代表单个字符和一个星号表示的零个或多个字符的序列:

if [[ $gg == ????grid* ]] ; then echo $gg; fi 

使用正则表达式时,点代表单个字符,星号代表零或更多前面的字符。因此,“.*”表示任意字符的零个或更多,“a*”表示零个或更多“a”,“[0-9]*”表示零个或更多个数字。另一个有用的(很多)是代表前面的一个或多个字符的加号。所以“[a-z]+”表示一个或多个小写字母字符(在C语言环境中 - 以及其他一些字符)。

if [[ $gg =~ ^....grid.*$ ]] ; then echo $gg; fi 
+0

所以字符串匹配有两种方法:glob模式和正则表达式? glob pettern不仅用于文件名吗?在bash中,何时使用glob模式以及何时使用正则表达式?谢谢! – Tim 2010-02-27 20:24:12

+0

@Tim:Globbing可用于大多数或所有版本的Bash。正则表达式匹配仅适用于版本3和更高版本,但我建议仅在3.2及更高版本中使用它。正则表达式比globbing更**更多。 – 2010-02-27 22:30:36

12
if [[ $gg =~ ^....grid.* ]] 
+1

您应该可以使用“。{4}”而不是“....”,即“^。{4} grid。*”。它可以更容易阅读和理解。 – user276648 2016-03-01 09:11:08

3

@OP,

Is glob pettern not only used for file names? 

没有, “水珠” 模式不仅可用于文件名。你也可以使用它来比较字符串。在你的例子中,你可以使用case/esac来查找字符串模式。

gg=svm-grid-ch 
# looking for the word "grid" in the string $gg 
case "$gg" in 
    *grid*) echo "found";; 
esac 

# [[ $gg =~ ^....grid* ]] 
case "$gg" in ????grid*) echo "found";; esac 

# [[ $gg =~ s...grid* ]] 
case "$gg" in s???grid*) echo "found";; esac 

In bash, when to use glob pattern and when to use regular expression? Thanks!

正则表达式更灵活,比“glob模式”,“方便”,但除非你正在做的复杂任务“通配符/扩展通配”不能轻易提供,那么就没有需要使用正则表达式。 正则表达式不支持版本的bash < 3.2(如丹尼斯提到的),但仍可以使用扩展匹配(通过设置extglob)。有关扩展匹配,请参阅here和一些简单示例here

更新OP:实施例发现,用2个字符(的点装置1个字符“”),接着的‘g’开头的文件使用正则表达式

例如输出

$ shopt -s dotglob 
$ ls -1 * 
abg 
degree 
..g 

$ for file in *; do [[ $file =~ "..g" ]] && echo $file ; done 
abg 
degree 
..g 

在上述,这些文件是匹配的,因为它们的名称包含2个字符,后面跟着“g”。 (即..g)。

用通配符会是这样的等价的:(看reference?意义和*

$ for file in ??g*; do echo $file; done 
abg 
degree 
..g 
+0

谢谢ghostdog74。在版本高于3.2的Bash中,可以使用正则表达式替换全局模式,无论后者出现在何处?或者正则表达式只能用于某些特殊情况?例如,我发现“ls ?? g”正在工作,而“ls ..g”不在。 – Tim 2010-02-28 03:42:14

+0

如果有需要的话,使用正则表达式并没有停止。随你便。请注意,regex语法与shell通配符语法不同。所以'ls ..g'不起作用。您正在告诉shell寻找一个名为'..g'的文件。至于学习正则表达式语法,你可以尝试'perldoc perlretut','perldoc perlrequick',或者在命令行上做一个'info sed'。 – ghostdog74 2010-02-28 04:19:47

5

添加具有grep这个解决方案和基本sh建宏为那些有兴趣在更便携的解决方案(独立的bash版本;也可与普通的旧sh,在非Linux平台等)

# GLOB matching 
gg=svm-grid-ch  
case "$gg" in 
    *grid*) echo $gg ;; 
esac 

# REGEXP  
if echo "$gg" | grep '^....grid*' >/dev/null ; then echo $gg ; fi  
if echo "$gg" | grep '....grid*' >/dev/null ; then echo $gg ; fi  
if echo "$gg" | grep 's...grid*' >/dev/null ; then echo $gg ; fi  

# Extended REGEXP 
if echo "$gg" | egrep '(^....grid*|....grid*|s...grid*)' >/dev/null ; then 
    echo $gg 
fi  

一些grep化身也支持-q(安静)选项作为重定向到/dev/null的替代方案,但重定向再次是最便携的。

+0

egrep忘记关闭“)” – ghostdog74 2010-02-28 02:19:35

+3

使用'grep -q'而不是'grep>/dev/null'。 – bfontaine 2016-05-18 16:27:22