【问题标题】:use regular expression in if-condition in bash在 bash 的 if 条件中使用正则表达式
【发布时间】:2011-01-21 20:19:01
【问题描述】:

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

为什么最后三个不匹配?

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

【问题讨论】:

    标签: regex bash


    【解决方案1】:
    if [[ $gg =~ ^....grid.* ]]
    

    【讨论】:

    • 您应该可以使用“.{4}”而不是“....”,即“^.{4}grid.*”。它可以更容易阅读和理解。
    【解决方案2】:

    使用 =~

    对于正则表达式检查Regular Expressions Tutorial Table of Contents

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

      • 那么字符串匹配有两种方式:glob模式和正则表达式? glob pettern 不仅用于文件名吗?在 bash 中,何时使用 glob 模式以及何时使用正则表达式?谢谢!
      • @Tim: Globbing 在大多数或所有版本的 Bash 中都可用。正则表达式匹配仅在版本 3 及更高版本中可用,但我建议仅在 3.2 及更高版本中使用它。正则表达式比通配符更通用。
      【解决方案4】:

      @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 模式,什么时候使用正则表达式?谢谢!

      Regex 比“glob 模式”更通用和“方便”,但是除非您正在执行“globbing/extended globbing”无法轻松提供的复杂任务,否则没有必要使用 regex。 bash 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)。

      globbing 的等效项是这样的:(查看reference 以了解?* 的含义)

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

      【讨论】:

      • 感谢 ghostdog74。在高于 3.2 版本的 Bash 中,可以使用正则表达式来替换 glob 模式出现的任何地方吗?还是正则表达式只能在某些特殊情况下使用?例如,我发现“ls ??g”正在工作,而“ls ..g”却没有。
      • 如果有需要,你可以使用正则表达式。由你决定。请注意,正则表达式语法与 shell 通配符语法不同。所以ls ..g 不起作用。您是在告诉 shell 查找名为 ..g 的文件。至于学习regex语法,可以试试perldoc perlretutperldoc perlrequick,或者在命令行下info sed
      【解决方案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 的替代方案,但重定向又是最便携的。

      【讨论】:

      • 忘记了 egrep 的结束符 ")"
      • 使用grep -q 而不是grep >/dev/null
      猜你喜欢
      • 2011-01-28
      • 1970-01-01
      • 1970-01-01
      • 2022-10-24
      • 1970-01-01
      • 1970-01-01
      • 2019-12-11
      • 2018-07-11
      • 2020-12-23
      相关资源
      最近更新 更多