如何检查文件名是否与shell脚本中的regex匹配

时间:2016-05-04 20:50:50

标签: bash shell

我有一个shell脚本,需要检查文件名是否与某个正则表达式匹配,但它总是显示“不匹配”。任何人都可以让我知道我的代码有什么问题吗?

fileNamePattern=abcd_????_def_*.txt
realFilePath=/data/file/abcd_12bd_def_ghijk.txt

if [[ $realFilePath =~ $fileNamePattern ]]
then
    echo $realFilePath match  $fileNamePattern
else
    echo $realFilePath not match $fileNamePattern
fi

2 个答案:

答案 0 :(得分:9)

正则表达式和更简单的" glob" /"通配符" /"正常"之间存在混淆。 模式 - 无论你想叫什么。你正在使用后者,但称之为正则表达式。

如果你想使用模式,你应该

  • 在分配 1 时引用它:

    fileNamePattern="abcd_????_def_*.txt"
    

    你还不想要任何东西扩展。

  • 使其与完整路径匹配。这不匹配:

    $ mypath="/mydir/myfile1.txt"
    $ mypattern="myfile?.txt"
    $ [[ $mypath == $mypattern ]] && echo "Matches!" || echo "Doesn't match!"
    Doesn't match!
    

    但是在将模式扩展为*之后:

    $ mypattern="*myfile?.txt"
    $ [[ $mypath == $mypattern ]] && echo "Matches!" || echo "Doesn't match!"
    Matches!
    

    第一个不匹配,因为它只匹配文件名,但不匹配完整路径。或者,您可以使用第一个模式,但使用parameter expansion删除路径的其余部分:

    $ mypattern="myfile?.txt"
    $ mypath="/mydir/myfile1.txt"
    $ echo "${mypath##*/}"
    myfile1.txt
    $ [[ ${mypath##*/} == $mypattern ]]  && echo "Matches!" || echo "Doesn't match!"
    Matches!
    
  • 使用==而非=~,如上例所示。您也可以使用更具可移植性的=,但由于我们已经使用非POSIX [[ ]]而不是[ ],我们也可以使用==

如果您想使用正则表达式,您应该:

  • 将您的模式编写为一个:?*在正则表达式中具有不同的含义;他们修改了他们所遵循的内容,而在glob模式中,他们可以自立(见the manual)。相应的模式将成为:

    fileNameRegex="abcd_.{4}_def_.*.txt"
    

    可以像这样使用:

    $ realFilePath="/data/file/abcd_12bd_def_ghijk.txt"
    $ [[ $mypath =~ $fileNameRegex ]] && echo "Matches!" || echo "Doesn't match!"
    Matches!
    
  • 养成将正则表达式写入单独参数然后在条件运算符[[ ]]中不加引号使用它的习惯,或者转义变得非常混乱 - 它在Bash版本中也更容易移植。

BashGuide有关于Bash中不同类型模式的great article

请注意,引用参数几乎总是一个好习惯。在[[ ]]中的条件表达式中不需要它,实际上右侧的解释抑制为模式或正则表达式。如果您使用[ ](它不支持正则表达式和模式),则需要引用以避免特殊字符和空字符串的意外副作用。

1 实际上,在这种情况下,完全完全为真。分配给变量时,manual表示发生以下情况:

  

[...]代字号扩展,参数和变量扩展,命令替换,算术扩展和引用删除[...]

即,没有路径名(glob)扩展。虽然在这种情况下使用

fileNamePattern=abcd_????_def_*.txt

与引用的版本一样有效,使用引号可以防止在许多其他情况下出现意外,并且只要模式中有空白就需要它。

答案 1 :(得分:2)

使用RegExs而不是通配符:

var splitted = 'http://www.test.info/?id=50&size=40'.split('&');
var urlWithoutAmpersand = splitted[0];
// now urlWithoutAmpersand => 'http://www.test.info/?id=50'
var sizeValue = splitted[1].split('=')[1] * 1;
// now sizeValue => 40

输出:

{ ~ }  » fileNamePattern="abcd_...._def_.*\.txt"                   ~
{ ~ }  » realFilePath=/data/file/abcd_12bd_def_ghijk.txt           ~
{ ~ }  » if [[ $realFilePath =~ $fileNamePattern ]]                ~
\ then
\     echo $realFilePath match  $fileNamePattern
\ else
\     echo $realFilePath not match $fileNamePattern
\ fi