【问题标题】:How can I match a string with a regex in Bash?如何在 Bash 中将字符串与正则表达式匹配?
【发布时间】:2013-06-29 13:11:17
【问题描述】:

我正在尝试编写一个包含函数的 bash 脚本,因此当给定 .tar.tar.bz2.tar.gz 等文件时,它使用 tar 和相关开关来解压缩文件。

我正在使用 if elif then 语句来测试文件名以查看它的结尾,但我无法使用正则表达式元字符来匹配它。

为了避免不断重写我在命令行中使用“测试”的脚本,我认为下面的语句应该可以工作,我已经尝试了括号、引号和元字符的所有可能组合,但仍然失败。

test sed-4.2.2.tar.bz2 = tar\.bz2$; echo $?
(this returns 1, false)

我确定问题很简单,而且我到处寻找,但我不知道该怎么做。有人知道我该怎么做吗?

【问题讨论】:

    标签: regex string bash


    【解决方案1】:

    要匹配正则表达式,您需要使用 =~ 运算符。

    试试这个:

    [[ sed-4.2.2.tar.bz2 =~ tar.bz2$ ]] && echo matched
    

    或者,您可以在 == 运算符中使用通配符(而不是正则表达式):

    [[ sed-4.2.2.tar.bz2 == *tar.bz2 ]] && echo matched
    

    如果不关心可移植性,我建议使用[[ 而不是[test,因为它更安全、更强大。详情请见What is the difference between test, [ and [[ ?

    【讨论】:

    • 注意第二个示例中的 glob 通配符匹配。在 [[ ]] 内部,* 没有像通常那样扩展,以匹配当前目录中匹配模式的文件名。您的示例有效,但很容易过度概括并错误地认为 * 意味着匹配任何任何上下文。它只在 [[ ]] 内部起作用。否则,它会扩展为现有文件名。
    • 我尝试在正则表达式上使用引号但失败了; this answer 帮助完成这项工作check="^a.*c$";if [[ "abc" =~ $check ]];then echo match;fi 我们需要将正则表达式存储在 var 上
    • 还要注意正则表达式(如在 perl 中)不能放在括号中:[[ sed-4.2.2.tar.bz2 == "*tar.bz2" ]] 不起作用。
    • FWIW,否定的语法(即不匹配)是[[ ! foo =~ bar ]]
    • dash 不支持-n 1 参数,也不会自动将其放入$REPLY 变量中。当心!
    【解决方案2】:

    执行此操作的函数

    extract () {
      if [ -f $1 ] ; then
          case $1 in
              *.tar.bz2)   tar xvjf $1    ;;
              *.tar.gz)    tar xvzf $1    ;;
              *.bz2)       bunzip2 $1     ;;
              *.rar)       rar x $1       ;;
              *.gz)        gunzip $1      ;;
              *.tar)       tar xvf $1     ;;
              *.tbz2)      tar xvjf $1    ;;
              *.tgz)       tar xvzf $1    ;;
              *.zip)       unzip $1       ;;
              *.Z)         uncompress $1  ;;
              *.7z)        7z x $1        ;;
              *)           echo "don't know '$1'..." ;;
          esac
      else
          echo "'$1' is not a valid file!"
      fi
    }
    

    其他说明

    针对上述评论中的水瓶座力量,We need to store the regex on a var

    变量 BASH_REMATCH 在匹配表达式后设置,${BASH_REMATCH[n]} 将匹配括在括号中的第 n 个组,即在以下 ${BASH_REMATCH[1]} = "compressed"${BASH_REMATCH[2]} = ".gz"

    if [[ "compressed.gz" =~ ^(.*)(\.[a-z]{1,5})$ ]]; 
    then 
      echo ${BASH_REMATCH[2]} ; 
    else 
      echo "Not proper format"; 
    fi
    

    (上面的正则表达式并不适用于文件命名和扩展名,但它适用于示例)

    【讨论】:

    • 另请注意,使用 BSD tar 您可以对所有格式使用“tar xf”,并且不需要单独的命令或此函数。
    • GNU tar 上的 a 或 BSD tar 上的 p 明确告诉它从扩展名中自动推断压缩类型。否则 GNU tar 不会自动执行此操作,我从 @GoodPerson 的评论中猜测 BSD tar 默认会执行此操作。
    • 7z 可以解压.. AR, ARJ, CAB, CHM, CPIO, CramFS, DMG, EXT, FAT, GPT, HFS, IHEX, ISO, LZH, LZMA, MBR, MSI, NSIS, NTFS 、QCOW2、RAR、RPM、SquashFS、UDF、UEFI、VDI、VHD、VMDK、WIM、XAR 和 Z。请参阅7-zip.org
    【解决方案3】:

    shopt -s nocasematch

    if [[ sed-4.2.2.$LINE =~ (yes|y)$ ]]
     then exit 0 
    fi
    

    【讨论】:

      【解决方案4】:

      我没有足够的代表在这里发表评论,所以我提交了一个新的答案来改进 dogbane 的答案。点。在正则表达式中

      [[ sed-4.2.2.tar.bz2 =~ tar.bz2$ ]] && echo matched

      实际上将匹配任何字符,而不仅仅是 'tar.bz2' 之间的文字点,例如

      [[ sed-4.2.2.tar4bz2 =~ tar.bz2$ ]] && echo matched
      [[ sed-4.2.2.tar§bz2 =~ tar.bz2$ ]] && echo matched
      

      或任何不需要用“\”转义的东西。 严格的语法应该是

      [[ sed-4.2.2.tar.bz2 =~ tar\.bz2$ ]] && echo matched
      

      或者你可以更严格,在正则表达式中包含前一个点:

      [[ sed-4.2.2.tar.bz2 =~ \.tar\.bz2$ ]] && echo matched
      

      【讨论】:

        【解决方案5】:

        由于您使用的是 bash,因此您无需为此创建子进程。这是一种完全在 bash 中执行的解决方案:

        [[ $TEST =~ ^(.*):\ +(.*)$ ]] && TEST=${BASH_REMATCH[1]}:${BASH_REMATCH[2]}
        

        说明:序列“冒号和一个或多个空格”前后的组被模式匹配运算符存储在 BASH_REMATCH 数组中。

        【讨论】:

        • 请注意,索引 0 包含完整匹配,索引 1 和 2 包含组匹配。
        【解决方案6】:
        if [[ $STR == *pattern* ]]
        then
            echo "It is the string!"
        else
            echo "It's not him!"
        fi
        

        为我工作! GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)

        【讨论】:

        • 这是极其危险的;它只会表现出对您没有未定义行为的行为,因为当前目录中没有名为文字子字符串“pattern”的文件。继续,创建一些这样命名的文件,子字符串扩展将匹配这些文件,并用五颜六色的 heisenbugs 破坏一切。
        • 但是我做了一个实验:在当前目录中使用文件`1pattern,patternpattern2和pattern。该脚本按预期工作。你能把你的测试结果提供给我吗? @i336_
        • @i336:我不这么认为。在[[ ... ]] 中,rhs glob 模式不会像通常那样根据当前目录扩展。
        • @i336_ 否。在[[...]] 内,Bash 不执行文件名扩展。在 bash 手册中,Word splitting and filename expansion are not performed on the words between the [[ and ]];
        • @juancortez :它也没有真正满足 OP 的要求,无论出于何种原因,他要求匹配 regexp
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-01
        • 2013-10-18
        • 2012-11-26
        • 2022-01-17
        • 2014-09-09
        • 1970-01-01
        相关资源
        最近更新 更多