【问题标题】:Use glob ** to match file extensions based on recursive parameter使用 glob ** 根据递归参数匹配文件扩展名
【发布时间】:2020-08-15 03:25:50
【问题描述】:

我正在尝试使用 glob 模式匹配具有给定扩展名的文件。 glob 函数(来自 glob 模块)有一个参数“recursive”,它似乎应该打开或关闭搜索子目录。但是,我一直无法构建一个 glob 模式,该模式仅在 recursive=False 时才会匹配当前目录中的某个类型的文件,如果 recursive=True 时也会匹配子目录中的文件。

folder='C:\\test'
glob(folder+'**.ext',recursive=True) #fails to find any files
glob(folder+'\\**.ext',recursive=True) #fails to search subfolders
glob(folder+'\\**',recursive=True) #fails to filter by type
glob(folder+'\\**\\*.ext',recursive=False) #searches subfolders when it shouldn't
glob(folder+'**\\*.ext',recursive=True) #fails to search subfolders

根据文档

"**" 将匹配任何文件和零个或多个目录

所以,我希望 ** 表现得像 * ,除了它也匹配斜杠。但是,它没有按预期工作(请参阅上面的前两个示例)。

为什么 ** 没有按预期工作,是否存在与某些文件类型匹配的模式,并且只能使用递归参数打开或关闭递归?

【问题讨论】:

    标签: python recursion filesystems glob


    【解决方案1】:

    我认为你误解了recursive=True 的含义。它用于允许** 表示搜索子目录到可变深度——glob(folder+'\\**\\*.ext',recursive=True) 将在起始文件夹或其下方的任何位置找到任何*.ext 文件。如果没有recursive=True** 将以正常方式解释,每个* 表示匹配任意数量的字符不包括\,因此** 将等同于* -- 换句话说,glob(folder+'\\**\\*.ext',recursive=False) 将搜索任何位于起始文件夹下一层子目录的*.ext 文件,但不在起始文件夹本身或更深的子目录中。

    您应该使用哪一个将取决于您要查找的内容——而且确实可能​​需要使用if 语句在不同的情况下进行选择——但没有使用@ 的用例987654334@ 和 recursive=False,因为在这种情况下,它只相当于 *

    最可能有用的选项是:

    glob(folder+'\\*.ext',recursive=False)  # search in top folder only
    glob(folder+'\\*\\*.ext',recursive=False)  # search exactly one level down
    glob(folder+'\\**\\*.ext',recursive=True)  # search to arbitrary depth
    

    ,recursive=False 可以省略,因为它是默认值。

    如果您想在使用布尔选项之间选择两个选项,您总是可以编写自己的包装函数,例如:

    def myglob(folder, pattern, subdirs=False):
        if subdirs:
            return glob(f'{folder}\\**\\{pattern}', recursive=True)
        else
            return glob(f'{folder}\\{pattern}')
    
    print(myglob(folder, '*.ext', subdirs=False))
    print(myglob(folder, '*.ext', subdirs=True))
    print(myglob(folder, '*.ext'))  # same as subdirs=False in this example
    

    (在类 Unix 操作系统中,请阅读 / 以获取上面的 \。)

    【讨论】:

    • 谢谢,我仍然不明白为什么我给出的前两个示例不起作用?为什么我不能在过滤给定文件扩展名的同时执行第 3 个(按预期工作,根据递归值切换)之类的操作?
    • @KalevMaricq 据我所知,虽然**recursive=True 旨在匹配任意数量的路径元素,但它不会匹配路径元素的 parts -- 所以你不应该将 **.ext 作为 glob 模式的一部分。
    【解决方案2】:

    glob '**'的操作

    glob 源代码可以在here 找到。除了 cmets,'**' 只出现在 _isrecursive 函数中:

    def _isrecursive(pattern):
        if isinstance(pattern, bytes):
            return pattern == b'**'
        else:
            return pattern == '**'
    

    因为 _isrecursive 函数使用相等运算符检查“”,所以“”只有在它是整个“模式”时才会按预期运行。 _isrecursive函数在源码中被调用了4次,整个glob调用一次,'basename'调用3次,定义为:

    dirname, basename = os.path.split(pathname)
    

    这被称为递归调用,一次从路径中拆分尾部,并且每次,basename 都是斜杠后面的所有内容(技术上是 os.sep,对于 Windows 是 \,对于 POSIX 是 /)。这意味着,为了使 '**' 能够按描述进行操作,它不得与斜杠以外的任何内容相邻

    如果 recursive 未明确设置为 True,则 '**' = '*'+'*' = '*' 因为 '*' 匹配 0 个或多个非斜杠字符。

    匹配扩展

    由于 '**' 的运作方式,它必须用于表示 glob 的整个级别。由于它代表 0 或更多 个级别,因此 r'folder\**\*.ext' 匹配 'folder' 中的文件以及子文件夹。但是,如果没有将 recursive 设置为 true,则此模式将仅匹配第一级子文件夹中的文件。

    '**.ext' 将不起作用,因为'**' 并不孤单。这留下了以下选项:

    1. 使用不同的库(例如 os.walk、pathlib.glob 等)

    2. [f for f in glob(folder+'\\**',recursive=subdirs) if f.endswith('.ext')]

    3. glob(folder+('\\**' if subdirs else '')+'\\*.ext, recursive=True)

      或者等价的,

      if recursive:
          glob(folder+'\\**\\*.ext', recursive=True)
      else:
          glob(folder+'\\*.ext')
      
    4. glob(folder+'\\..\\**\\*.ext', recursive=subdirs) #not recommended since it will also match files in sibling folders

    【讨论】:

      猜你喜欢
      • 2011-08-31
      • 1970-01-01
      • 1970-01-01
      • 2019-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多