代码之家  ›  专栏  ›  技术社区  ›  singmotor

递归地查找文件类型列表

  •  3
  • singmotor  · 技术社区  · 6 年前

    我想使用bash删除目录中不在文件扩展名关联数组中的所有文件。(例如,删除目录中不是图像文件的所有文件)

    This question 很清楚地回答了如何对单个文件扩展名执行此操作,但我不确定如何对整个列表执行此操作。

    现在我在做 this

    for f in $(find . -type f ! -name '*.png' -and ! -name '*.jpg' ); do rm "$f"; done
    

    但是在每个文件类型的括号内添加大量“-and-name'*.a a a'”看起来很难看。

    有路可走吗 find 类似于

    declare -A allowedTypes=([*.png]=1 [*.jpg]=1 [*.gif]=1)
    

    或者我只需要添加很多“-而且!-名字?

    谢谢!

    2 回复  |  直到 6 年前
        1
  •  3
  •   Inian    6 年前

    使用的整个想法 find 首先是 需要。壳体球形支架 bash 足以满足这一要求。这个 猛击 shell提供了一个扩展的glob支持选项,您可以使用该选项在递归路径下获取文件名,这些路径不会以要忽略的扩展名结尾。

    扩展选项是 extglob 需要使用 shopt 选项如下。此外,您还可以使用两个选项。 nullglob 其中一个不匹配的球被完全扫除,取而代之的是一组零字。以及 globstar 允许在所有目录中递归

    shopt -s extglob nullglob globstar
    

    现在您只需要形成glob表达式来排除类型为 *.png , *.jpg *.gif 你可以这样做。我们使用数组填充glob结果,因为当正确引用并展开时,带有特殊字符的文件名将保持完整

    fileList=(**/!(*.jpg|*.gif|*.png))
    

    选择权 ** 是通过子文件夹和 !() 是一个否定操作,不包含其中列出的任何文件扩展名。现在打印实际文件,只要

    printf '%s\n' "${fileList[@]}"
    

    例如,如果您的目的是删除标识的所有文件,则不需要将glob结果存储在数组中。在编写需要使用glob结果的简单shell脚本时,可以使用数组方法。但是对于删除文件的情况,可以使用 rm 命令。

    首先你可以检查返回的文件是否 作为 一旦你确认你可以 在表情上。使用 ls 查看文件是否按预期列出

    ls -1 -- **/!(*.jpg|*.gif|*.png)
    

    现在确认要删除的文件后,执行 风险自负。

    rm -- **/!(*.jpg|*.gif|*.png)
    
        2
  •  1
  •   Rayne    6 年前

    假设 : allowedTypes 只包含受信任的输入和有效的后缀。

    第一个代码片段支持多级后缀,如 tar.gz . 它使用 find ,正则表达式和允许的后缀列表 允许的类型 .

    allowedTypes=(png gif jpg)
    
    # keepTypes='png|gif|jpg'
    keepTypes="$(echo "${allowedTypes[@]}" | tr ' ' '|')"
    
    find . -type f -regextype awk ! -iregex '(.*).('"$keepTypes"')' -exec echo rm {} \;
    

    如果要保留关联数组,则可以使用以下代码段。 它需要额外的工作来支持多级文件后缀。

    declare -A allowedTypes=([*.png]=1 [*.jpg]=1 [*.gif]=1)
    
    keepTypes="$(echo "${!allowedTypes[@]}" | tr ' ' '|' | tr -d '.*')"
    

    如果有办法用内置工具代替 tr 但我什么也没找到。 ${allowedTypes[@]//\ /test} 没有替换项之间的空白。