2010-02-27 62 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