【问题标题】:Using find to locate files that match one of multiple patterns使用 find 查找与多个模式之一匹配的文件
【发布时间】:2020-12-30 19:42:34
【问题描述】:

我试图使用命令find Documents -name "*.{py,html}" 获取目录中所有 python 和 html 文件的列表。

然后是手册页:

模式 ('{}') 中的大括号不被认为是特殊的(即 find .-name 'foo{1,2}' 匹配名为 foo{1,2} 的文件,而不是文件 foo1和 foo2。

由于这是管道链的一部分,我希望能够指定它在运行时匹配哪些扩展(无硬编码)。如果 find 做不到,那么 perl 单行(或类似的)就可以了。

编辑:我最终想出的答案包括各种废话,而且也有点长,所以我将它作为an answer 发布到我试图从头开始的痒处。如果您有更好的解决方案,请随意破解。

【问题讨论】:

标签: shell find


【解决方案1】:

使用-o,表示“或”:

find Documents \( -name "*.py" -o -name "*.html" \)

您需要以编程方式构建该命令行,这并不容易。

您使用的是 bash(或 Windows 上的 Cygwin)吗?如果你是,你应该能够做到这一点:

ls **/*.py **/*.html

这可能更容易以编程方式构建。

【讨论】:

  • 我使用的是 zsh,它通常支持所有的 bashism 以及更多。
  • Zsh 支持** 进行递归搜索; Bash 仅在 4.0 及更高版本中支持它,并且仅支持 shopt -s globstar
  • 你可以有多少个 -o 参数?我有一个可能很大的 .gcda(覆盖数据)文件列表来构建
  • 如果您使用的是-exec,则需要用括号括住两个-name。例如。 find Documents \( -name "*.py" -o -name "*.html" \) -exec file {} \;
  • @artbristol 注释非常相关,例如,如果您要添加 -print0 来处理带空格的文件名。
【解决方案2】:

find 的某些版本,主要在 linux 系统上,可能在其他系统上还支持 -regex 和 -regextype 选项,它们会查找名称与 regex 匹配的文件。

例如

find . -regextype posix-egrep -regex ".*\.(py|html)$" 

应该在上面的例子中做到这一点。 但是,这不是标准的 POSIX 查找函数,并且依赖于实现。

【讨论】:

  • 更简单:find . -regex ".*\.\(py\|html\)$" 之所以有效,是因为 find 默认为 Emacs 样式的正则表达式,它们略有不同,因此您不必指定 regextype。
  • 如果你有很多表达式-regextype posix-egrep 很方便(否则你需要转义很多字符)。这是我用于构建 Windows 分发 zip 的 dist-hook 的 find 命令(查找要更改的文件并在文件内将它们更改为 dos-eol):find -regextype posix-egrep -regex ".*(\.([chyl]|def|cpy|cob|conf|cfg)|(README|ChangeLog|AUTHORS|ABOUT-NLS|NEWS|THANKS|TODO|COPYING.*))$" -exec sed -i -e 's/\r*$/\r/' {} \;
【解决方案3】:

您可以以编程方式添加更多-name 子句,以-or 分隔:

find Documents \( -name "*.py" -or -name "*.html" \)

或者,改为使用简单的循环:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done

【讨论】:

  • 是 -or 还是 -o ?
  • @StephaneEybert:两者都可以,但只有后者符合 POSIX(根据手册页)。
  • 这对我在 macOS 上递归不起作用。与子目录中的文件一样。
【解决方案4】:

这将在 linux 上找到所有 .c 或 .cpp 文件

$ find . -name "*.c" -o -name "*.cpp"

除非你正在做一些额外的模组,否则你不需要转义括号。他们在手册页中说如果模式匹配,请打印它。也许他们正试图控制印刷。在这种情况下, -print 充当条件并成为“AND'd”条件。它将阻止打印任何 .c 文件。

$ find .  -name "*.c" -o -name "*.cpp"  -print

但是,如果您确实喜欢原始答案,则可以控制打印。这也会找到所有 .c 文件。

$ find . \( -name "*.c" -o -name "*.cpp" \) -print

所有 c/c++ 源文件的最后一个示例

$ find . \( -name "*.c" -o -name "*.cpp"  -o -name "*.h" -o -name "*.hpp" \) -print

【讨论】:

    【解决方案5】:

    我也有类似的需求。这对我有用:

    find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print
    

    【讨论】:

    • 我想找到匹配 *.c *.cpp 或 *.cc 的文件 只有两个 -name 模式我不需要括号,但三个 -name 模式与两个 -o 模式相结合@ 987654322@ 我不得不使用一对括号来对第二个或运算符进行分组。 find -name "*.cpp" -o \( -name "*.c" -o -name "*.cc" \) -print0 可能是 -print0 总是“true”影响了逻辑。
    【解决方案6】:

    我的默认设置是:

    find -type f | egrep -i "*.java|*.css|*.cs|*.sql"

    就像 Brendan Long 和 Stephan202 等人执行的更少的流程 intencive find

    find Documents \( -name "*.py" -or -name "*.html" \)

    【讨论】:

    • 这不是egrep 正则表达式的正确使用,相反,您有一个shell glob,应该使用正则表达式。 (另外,find 的典型用法是:find {directory} [options...] [action],其中,根据 impl,directory 可能默认为 .,而 action 默认为 -print,但我会明确说明。)所以,相反,使用类似的东西:find . -type f -print | egrep -i '\.java$|\.css$|\.cs$|\.sql$' 但是,作为find 的真正快速替代品,人们也可以以类似的方式尝试locate(尽管不一定是最新的,因为它会查询内部数据库以获取文件列表)
    【解决方案7】:

    \(\) 模式中的大括号对于带有or 的名称模式是必需的

    find Documents -type f \( -name "*.py" -or -name "*.html" \)
    

    虽然对于带有and 运算符的名称模式,它不是必需的

    find Documents -type f ! -name "*.py" -and ! -name "*.html" 
    

    【讨论】:

      【解决方案8】:
      #! /bin/bash
      filetypes="*.py *.xml"
      for type in $filetypes
      do
      find Documents -name "$type"
      done
      

      简单但有效:)

      【讨论】:

        【解决方案9】:

        我需要删除子目录中的所有文件,除了一些文件。以下对我有用(指定了三种模式):

        find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +
        

        【讨论】:

          【解决方案10】:

          这适用于 AIX korn shell。

          find *.cbl *.dms -prune -type f -mtime -1
          

          这是寻找 *.cbl*.dms 1 天前,仅在当前目录中,跳过子目录。

          【讨论】:

            【解决方案11】:
            find MyDir -iname "*.[j][p][g]"
            +
            find MyDir -iname "*.[b][m][p]"
            =
            find MyDir -iname "*.[jb][pm][gp]"
            

            【讨论】:

            • 请注意,后者将匹配 foo.jmg 但前两个都不会。
            【解决方案12】:

            怎么样

            ls {*.py,*.html}
            

            它列出了所有文件名中以 .py 或 .html 结尾的文件

            【讨论】:

              猜你喜欢
              • 2010-12-02
              • 1970-01-01
              • 1970-01-01
              • 2013-10-19
              • 2011-06-28
              • 2018-07-17
              • 1970-01-01
              • 2016-01-19
              • 1970-01-01
              相关资源
              最近更新 更多