【问题标题】:Why doesn't find let me match multiple patterns?为什么找不到让我匹配多个模式?
【发布时间】:2015-04-04 12:16:09
【问题描述】:

我正在编写一些处理某些文件的 bash/zsh 脚本。我想为某种类型的每个文件执行一个命令,其中一些命令重叠。当我尝试find -name 'pattern1' -or -name 'pattern2' 时,只使用最后一个模式(不返回匹配pattern1 的文件;只返回匹配pattern2 的文件)。我想要的是匹配pattern1pattern2 的文件。

例如,当我尝试以下操作时,这就是我得到的结果(注意仅找到并打印了 ./foo.xml):

$ ls -a
.        ..       bar.html foo.xml
$ tree .
.
├── bar.html
└── foo.xml

0 directories, 2 files
$ find . -name '*.html' -or -name '*.xml' -exec echo {} \;
./foo.xml
$ type find
find is an alias for noglob find
find is /usr/bin/find

使用-o 代替-or 会得到相同的结果。如果我切换-name 参数的顺序,则只返回bar.html 而不是foo.xml

为什么没有找到并返回bar.htmlfoo.xml?如何匹配多个模式?

【问题讨论】:

    标签: macos bash shell unix zsh


    【解决方案1】:

    查找实用程序

    -print == 默认

    如果你只想打印文件路径和名称,你必须删除exec echo,因为-print是默认的。:

    find . -name '*.html' -or -name '*.xml'
    

    订单依赖

    否则find从左到右读取,参数顺序很重要!

    因此,如果您想指定某些内容,请尊重 andor 优先级:

    find . -name '*.html' -exec echo ">"{} \;  -o -name '*.xml' -exec echo "+"{} \;
    

    find . -maxdepth 4 \( -name '*.html' -o -name '*.xml' \) -exec echo {} \;
    

    表达式-print0xargs 命令。

    但是,在大多数情况下,您可以考虑使用 -print0xargs 命令,例如:

    find . \( -name '*.html' -o -name '*.xml' \) -print0 |
        xargs -0 printf -- "-- %s -\n"
    

    这样做的好处是:

    • 只有一个(或少数)fork 用于发现数千个条目。 (使用-exec echo {} \; 意味着为找到的每个 条目运行一个子进程,而xargs 将构建一个长行,其中包含一个命令行可以容纳的尽可能多的参数...)

    • 为了处理包含特殊字符或空格的文件名,-print0xargs -0 将使用 NULL 字符作为文件名分隔符。

      李>

    find ... -exec ... {} ... +

    从几年前开始,find 命令接受-exec 开关的新语法。

    -exec 开关可以以加号 + 结尾,而不是 \;

    find . \( -name '*.html' -o -name '*.xml' \) -exec printf -- "-- %s -\n" {} +
    

    使用这种语法,find 将像 xargs 命令一样工作,构建长命令行以减少分叉。

    【讨论】:

    • 不使用-print0xargs,您还可以通过使用-exec COMMAND {} +而不是-exec COMMAND {} ;来减少分叉的数量,即用-exec而不是+终止\;。所以find .\ -name '*.html' -o -name '*.xml' \) -exec printf "\-- %s -\n" {} + 应该用更少的输入来做同样的事情。 (还要注意 ` before --` 是必需的 - 至少在我的系统上 - 以防止 printf 将整个引用模式解释为命令行参数)。
    • 嗯,有趣的新选项,感谢@Adaephon。但我怀疑在某些不同的 find 实现中可能不存在此选项...
    • @Adaephon: 好点回复-exec ...+;在操作数(非选项)中重新解释--(或-):处理此问题的可移植方法是使用特殊选项--before操作数明确表示后面的内容是操作数,而不是选项:printf -- "-- %s -n \n" {}
    • -exec ... + 符合 POSIX 标准;请参阅pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html,因此比非标准的-print0 操作更可取;另外-exec ... + 需要更少的输入,它也比-print0 / xargs 组合更有效。
    【解决方案2】:

    您需要在find 命令中使用括号对条件进行分组,否则只有第二个-name 选项对-exec 命令有效。

    find . \( -name '*.html' -or -name '*.xml' \) -exec echo {} \;
    

    【讨论】:

    • 酷,我没有意识到您可以将它们分组到不同的执行组中(即find . -name 'pattern1' -exec cmd1 \; -o -name 'pattern2' -exec cmd2 \;(并且省略-o 只会导致第一个“组”被使用和执行))。
    • 是的,确实有 2 个不同的 -exec 也是可能的。
    猜你喜欢
    • 2013-04-12
    • 2012-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-02
    • 1970-01-01
    • 2020-09-18
    • 2021-01-24
    相关资源
    最近更新 更多