如何在Bash中将字符串与正则表达式匹配?


166

我想写一个包含函数,以便给出当bash脚本.tar.tar.bz2.tar.gz等文件,它使用的焦油与相关的开关来解压缩文件。

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

为了避免经常在命令行中使用“ test”来重写脚本,我认为下面的语句应该起作用,我尝试了括号,引号和元字符的所有组合,但仍然失败。

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

我敢肯定,问题很简单,我到处都看过,但是我无法理解该怎么做。有人知道我该怎么做吗?

Answers:


268

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

试试这个:

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

另外,您可以对==运算符使用通配符(而不是正则表达式):

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

如果不考虑可移植性,我建议使用[[代替[或,test因为它更安全,更强大。请参见test,[和[[有什么区别?有关详细信息。


7
在第二个示例中,请谨慎使用glob通配符匹配。在[[]]内部,*不会像通常那样扩展,以匹配当前目录中与模式匹配的文件名。您的示例有效,但过分泛化确实很容易,并且错误地认为*表示可以匹配任何上下文。它仅在[[]]内部起作用。否则,它将扩展为现有的文件名。
艾伦·波特

7
我试图在正则表达式上使用引号,但失败了。这个答案有助于完成这项工作,check="^a.*c$";if [[ "abc" =~ $check ]];then echo match;fi我们需要将正则表达式存储在var
Aquarius Power

还要注意,正则表达式(如perl中的)不能用括号括起来:[[ sed-4.2.2.tar.bz2 == "*tar.bz2" ]]不起作用。
pevik

18
FWIW,否定(即不匹配)的语法为[[ ! foo =~ bar ]]
Skippy le Grand Gourou

1
破折号不支持-n 1参数,也不会自动将其放入$REPLY变量。小心!

54

一个功能来做到这一点

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

(上面的regex并不是有效的文件命名和扩展名,但适用于示例)


还请注意,使用BSD tar可以对所有格式使用“ tar xf”,不需要任何单独的命令或此功能。
好人

a在GNU tar或pBSD tar上显式告诉它从扩展名自动推断压缩类型。否则,GNU tar不会自动执行此操作,而我从@GoodPerson的评论中猜测,BSD tar默认会执行此操作。
Mark K Cowan

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
mosh,

14

我的代表没有足够的评论,因此,我正在提交一个新的答案,以改善狗狗的答案。点。在正则表达式中

[[ 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

9

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

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

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


1
请注意,索引0包含完全匹配项,索引1和2包含组匹配项。
Rainer Schwarze

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


1
这是非常危险的;它只会为您带来不确定的行为,因为当前目录中没有名为文字子字符串“ pattern”的文件。继续,创建一些像这样的文件,子字符串扩展将匹配这些文件,并使用彩色的heisenbug破坏所有内容。
i336_ '18

但是我做了一个实验:在当前目录中使用文件`1pattern,pattern pattern2和pattern。该脚本按预期工作。能否请您提供测试结果?@ i336_
juan

2
@ i336:我不这么认为。内[[ ... ]],在RHS glob模式并没有按照寿当前目录扩大,因为它通常会做的。
user1934428

@ i336_否。在中[[...]],Bash不会执行文件名扩展。在bash手册中,Word splitting and filename expansion are not performed on the words between the [[ and ]];
jinbeom hong

@jinbeomhong:TIL。很高兴知道,谢谢!
i336_

2

shopt -s nocasematch

if [[ sed-4.2.2.$LINE =~ (yes|y)$ ]]
 then exit 0 
fi
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.