为什么找不到让我匹配多个模式?
Why doesn't find let me match multiple patterns?
我正在编写一些 bash/zsh 脚本来处理一些文件。我想对某个类型的每个文件执行一个命令,其中一些命令是重叠的。当我尝试 find -name 'pattern1' -or -name 'pattern2'
时,仅使用最后一个模式(不返回匹配 pattern1
的文件;仅返回匹配 pattern2
的文件)。我想要的是匹配 pattern1
或 pattern2
的文件。
例如,当我尝试以下操作时,这就是我得到的(注意仅找到并打印 ./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.html
和 foo.xml
?如何匹配多个模式?
您需要在 find
命令中使用括号来对您的条件进行分组,否则只有第二个 -name
选项对 -exec
命令有效。
find . \( -name '*.html' -or -name '*.xml' \) -exec echo {} \;
寻找实用程序
-print
== 默认值
如果你只想打印文件路径和名称,你必须删除 exec echo
,因为 -print
是默认值。:
find . -name '*.html' -or -name '*.xml'
订单依赖性
否则,find
从左到右阅读,参数顺序很重要!
因此,如果您想指定某些内容,请遵守 and
和 or
优先级:
find . -name '*.html' -exec echo ">"{} \; -o -name '*.xml' -exec echo "+"{} \;
或
find . -maxdepth 4 \( -name '*.html' -o -name '*.xml' \) -exec echo {} \;
表达式-print0
和xargs
命令。
但是,在大多数情况下,您可以考虑使用 -print0
命令和 xargs
命令,例如:
find . \( -name '*.html' -o -name '*.xml' \) -print0 |
xargs -0 printf -- "-- %s -\n"
这样做的好处是:
只有一个(或少数)fork 找到了数千个条目。 (使用 -exec echo {} \;
意味着一个子进程是 运行 对于 找到的每个 条目,而 xargs
将构建一长行,其中包含一个命令行的参数可以容纳...)
为了处理包含特殊字符或空格的文件名,-print0
和 xargs -0
将使用 NULL
字符作为文件名分隔符。
查找...-exec...{}...+
几年前,find
命令接受 -exec
开关的新语法。
而不是 \;
,-exec
开关可以以加号 +
结尾。
find . \( -name '*.html' -o -name '*.xml' \) -exec printf -- "-- %s -\n" {} +
使用此语法,find
将像 xargs
命令一样工作,构建长命令行以减少分叉。
我正在编写一些 bash/zsh 脚本来处理一些文件。我想对某个类型的每个文件执行一个命令,其中一些命令是重叠的。当我尝试 find -name 'pattern1' -or -name 'pattern2'
时,仅使用最后一个模式(不返回匹配 pattern1
的文件;仅返回匹配 pattern2
的文件)。我想要的是匹配 pattern1
或 pattern2
的文件。
例如,当我尝试以下操作时,这就是我得到的(注意仅找到并打印 ./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.html
和 foo.xml
?如何匹配多个模式?
您需要在 find
命令中使用括号来对您的条件进行分组,否则只有第二个 -name
选项对 -exec
命令有效。
find . \( -name '*.html' -or -name '*.xml' \) -exec echo {} \;
寻找实用程序
-print
== 默认值
如果你只想打印文件路径和名称,你必须删除 exec echo
,因为 -print
是默认值。:
find . -name '*.html' -or -name '*.xml'
订单依赖性
否则,find
从左到右阅读,参数顺序很重要!
因此,如果您想指定某些内容,请遵守 and
和 or
优先级:
find . -name '*.html' -exec echo ">"{} \; -o -name '*.xml' -exec echo "+"{} \;
或
find . -maxdepth 4 \( -name '*.html' -o -name '*.xml' \) -exec echo {} \;
表达式-print0
和xargs
命令。
但是,在大多数情况下,您可以考虑使用 -print0
命令和 xargs
命令,例如:
find . \( -name '*.html' -o -name '*.xml' \) -print0 |
xargs -0 printf -- "-- %s -\n"
这样做的好处是:
只有一个(或少数)fork 找到了数千个条目。 (使用
-exec echo {} \;
意味着一个子进程是 运行 对于 找到的每个 条目,而xargs
将构建一长行,其中包含一个命令行的参数可以容纳...)为了处理包含特殊字符或空格的文件名,
-print0
和xargs -0
将使用NULL
字符作为文件名分隔符。
查找...-exec...{}...+
几年前,find
命令接受 -exec
开关的新语法。
而不是 \;
,-exec
开关可以以加号 +
结尾。
find . \( -name '*.html' -o -name '*.xml' \) -exec printf -- "-- %s -\n" {} +
使用此语法,find
将像 xargs
命令一样工作,构建长命令行以减少分叉。