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

ig9co6j1  于 2023-02-13  发布在  Shell
关注(0)|答案(2)|浏览(193)

我有一个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
jgwigjjp

jgwigjjp1#

在 * regex * 和更简单的“glob”/“wildcard”/“normal”patterns 之间有一个混淆--不管你怎么称呼它们,你使用的是后者,但称它为regex。
如果要使用模式,则应

  • 赋值时引用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!

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

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

如果您想使用regex,您应该:

  • 把你的模式写成一个:?*在正则表达式中有不同的含义;它们会修改自己的立场,而在glob模式中,它们可以自己站起来(见手册)。2相应的模式将变成:
fileNameRegex='abcd_.{4}_def_.*\.txt'

可以这样使用:

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

BashGuide有一个关于Bash中不同类型模式的great article
请注意,引用参数几乎总是一个好习惯。在[[ ]]的条件表达式中不需要引用参数,实际上它 * 抑制 * 了将右侧解释为模式或正则表达式。如果您使用[ ](它不支持正则表达式和模式),则需要引用参数,以避免特殊字符和空字符串的意外副作用。
[1]实际上,在这个例子中并不完全正确,当赋值给一个变量时,手册上说会发生以下情况:
[...]波浪号扩展、参数和变量扩展、命令替换、算术扩展和引号删除[...]
例如,* 无路径名(glob)扩展 *。而在这种情况下,使用

fileNamePattern=abcd_????_def_*.txt

将与带引号的版本工作得一样好,使用引号可以防止在许多其他情况下出现意外,并且在模式中有空格时就需要使用引号。

wfypjpf4

wfypjpf42#

使用RegExs而不是通配符:

{ ~ }  » 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

输出:

/data/file/abcd_12bd_def_ghijk.txt match abcd_...._def_.*\.txt

相关问题