为什么 [az] 星号匹配数字?

为什么 [az] 星号匹配数字?

我当前路径有 3 个目录。

$ls
a_0db_data  a_clean_0db_data  a_clean_data
$ls a_*_data
a_0db_data:

a_clean_0db_data:

a_clean_data:

$ls a_[a-z]*_data
a_clean_0db_data:

a_clean_data:

我预计最后一个 ls 命令仅匹配a_clean_data.为什么它也匹配包含的那个0

bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)

答案1

零件[a-z]与数字不匹配;这是*.你可能对 shell 感到困惑通配常用表达

grep诸如接受各种风格的正则表达式之类的工具(基本的默认情况下,-E对于扩展,-P对于Perl正则表达式

例如(-v反转匹配)

$ ls a_[a-z]*_data | grep -v "[0-9]"
a_clean_data

如果您想使用 bash 正则表达式,这里有一个关于如何测试变量是否$ref为整数的示例:

re='^[0-9]+$'
if ! [[ $ref =~ $re ]] ; then
  echo "error"
fi

答案2

所以问题是:为什么a_[a-z]*_data匹配a_clean_0db_data

这可以分解为部分:

  • a_匹配 的开头a_clean_0db_data,留下clean_0db_data待匹配

  • [a-z]匹配范围内的任何字符a-z(例如c),留下lean_0db_data待匹配

  • *匹配任意数量的字符,例如lean_0db

  • _data匹配尾随的_data

在正则表达式中,[a-z]*意味着a..z 范围内的任意数量的字符(包括零个),但您正在处理 shell 通配符,而不是正则表达式。

如果您需要正则表达式,一些find实现有一个-regex谓词:

find . -maxdepth 1 -regex "^.*/a_[a-z]*_data$"

此处-maxdepth仅将搜索结果限制为您所在的文件夹。正则表达式匹配全部的文件名,因此我添加了一个^.*/来匹配路径部分

答案3

*在 shell 模式中匹配 0 个或多个字符。不要与*正则表达式运算符混淆,这意味着0 个或多个前面的原子

*基本 shell 模式中没有与 regexp 等效的东西。然而,各种 shell 对此都有扩展。

  • ksh*(something)

    ls a_*([a-z])_data
    
  • bash你可以在withshopt -s extglobzshwith中拥有相同的内容setopt kshglob

    shopt -s extglob
    ls a_*([a-z])_data
    
  • 在启用zshextendedglob#相当于 regexp *

    setopt extendedglob
    ls a_[a-z]#_data
    
  • 在最新版本的 中ksh93,您还可以在 glob 中使用正则表达式。这里与扩展常用表达:

    ls ~(E:a_[a-z]*_data)
    

请注意,[a-z]根据当前区域设置匹配不同的内容。它通常只匹配区域设置中的 26az拉丁非重音字母C。在其他语言环境中,它通常匹配更多,但并不总是有意义。要匹配您所在区域中的字母,您可能更喜欢[[:alpha:]].

相关内容