在bash中的if-condition中使用正则表达式


88

我想知道在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  
$   

为什么最后三个不匹配?

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

Answers:


128

使用全局模式时,问号代表单个字符,星号代表零个或多个字符的序列:

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

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

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

字符串匹配有两种方式:全局模式和正则表达式?glob pettern不仅用于文件名吗?在bash中,何时使用glob模式以及何时使用正则表达式?谢谢!
蒂姆(Tim)2010年

1
@Tim:在大多数或所有版本的Bash中都可以使用Globbing。正则表达式匹配仅在版本3和更高版本中可用,但我建议仅在3.2和更高版本中使用它。正则表达式比通配通用得多。
暂停,直到另行通知。



7

为那些对更便携式解决方案感兴趣的人(独立于版本;还可以在非Linux平台上与纯旧版本一起使用)添加此解决方案grep和基本的sh内置函数。bashsh

# 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(quiet)选项,作为重定向到的替代方法/dev/null,但是重定向仍然是最可移植的。


忘记了egrep的结尾“)”
ghostdog74

5
使用grep -q代替grep >/dev/null
bfontaine

3

@OP,

glob pettern不仅用于文件名吗?

不,“ glob”模式不仅用于文件名。您也可以使用它来比较字符串。在示例中,您可以使用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

在bash中,何时使用glob模式以及何时使用正则表达式?谢谢!

正则表达式比“全局模式”更通用,更“方便”,但是,除非您要执行“全局/扩展全局”无法轻松提供的复杂任务,否则就无需使用正则表达式。bash <3.2的版本不支持正则表达式(如dennis所述),但是您仍然可以使用扩展的globlob(通过设置extglob)。延长通配,见这里和一些简单的例子在这里

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)。

与遍历等效的内容将是这样的:(请参阅参考资料,了解?and的含义*

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

谢谢ghostdog74。在版本高于3.2的Bash中,是否可以使用正则表达式替换glob模式?还是只能在某些特殊情况下使用正则表达式?例如,我发现“ ls?g”正在工作,而“ ls ..g”却没有。
蒂姆(Tim)2010年

如果需要,您不会停止使用正则表达式。由你决定。注意,正则表达式语法与Shell Globlob语法不同。因此ls ..g不起作用。您要告诉外壳程序查找名为的文件..g。至于学习正则表达式的语法,你可以尝试perldoc perlretutperldoc perlrequick或做info sed在命令行上。
ghostdog74
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.