ChatGPT解决这个技术问题 Extra ChatGPT

如何在 find 命令中使用正则表达式?

我有一些用生成的 uuid1 字符串命名的图像。例如 81397018-b84a-11e0-9d2a-001b77dc0bed.jpg。我想使用“查找”命令找出所有这些图像:

find . -regex "[a-f0-9\-]\{36\}\.jpg".

但它不起作用。正则表达式有问题吗?有人可以帮我解决这个问题吗?

也许改变正则表达式。默认是 Emacs 正则表达式,不管是什么意思。

S
Susam Pal
find . -regextype sed -regex ".*/[a-f0-9\-]\{36\}\.jpg"

请注意,您需要在开头指定 .*/,因为 find 匹配整个路径。

例子:

susam@nifty:~/so$ find . -name "*.jpg"
./foo-111.jpg
./test/81397018-b84a-11e0-9d2a-001b77dc0bed.jpg
./81397018-b84a-11e0-9d2a-001b77dc0bed.jpg
susam@nifty:~/so$ 
susam@nifty:~/so$ find . -regextype sed -regex ".*/[a-f0-9\-]\{36\}\.jpg"
./test/81397018-b84a-11e0-9d2a-001b77dc0bed.jpg
./81397018-b84a-11e0-9d2a-001b77dc0bed.jpg

我的查找版本:

$ find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Built using GNU gnulib version e5573b1bad88bfabcda181b9e0125fb0c52b7d3b
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION FTS() CBO(level=0) 
susam@nifty:~/so$ 
susam@nifty:~/so$ find . -regextype foo -regex ".*/[a-f0-9\-]\{36\}\.jpg"
find: Unknown regular expression type `foo'; valid types are `findutils-default', `awk', `egrep', `ed', `emacs', `gnu-awk', `grep', `posix-awk', `posix-basic', `posix-egrep', `posix-extended', `posix-minimal-basic', `sed'.

@Tom 这是 find 中正则表达式的工作方式。根据手册页,正则表达式匹配整个文件路径,包括目录,这意味着您的正则表达式周围有一个隐含的 "^ ... $" 。它必须与整个结果行匹配。
我认为您不需要 .*/ 中的 /,因为 .* 匹配零个或多个(几乎)任何字符。
对于那些(像我一样)第一次没有正确阅读正则表达式的人:注意特殊正则表达式字符之前的反斜杠,例如:\{36\}
我找不到完整的正则表达式类型列表(联机帮助页不是最新的):valid types are 'findutils-default', 'awk', ' egrep', 'ed', 'emacs', 'gnu-awk', 'grep', 'posix-awk', 'posix-basic', 'posix-egrep', 'posix -extended', 'posix-minimal-basic', 'sed'.
确保将 -regextype 标志放在 -regex 标志之前,否则它不适用!
P
Paŭlo Ebermann

-regex find 表达式匹配全名,包括当前目录的相对路径。对于 find .,它始终以 ./ 开头,然后是任何目录。

此外,这些是 emacs 正则表达式,除了通常的 egrep 正则表达式之外,它们还有其他转义规则。

如果这些都直接在当前目录下,那么

find . -regex '\./[a-f0-9\-]\{36\}\.jpg'

应该管用。 (我不太确定 - 我无法让计数重复在这里工作。)您可以通过 -regextype posix-egrep 切换到 egrep 表达式:

find . -regextype posix-egrep -regex '\./[a-f0-9\-]{36}\.jpg'

(请注意,这里所说的一切都是针对 GNU 查找的,我对 BSD 一无所知,这也是 Mac 上的默认设置。)


我的正则表达式中有多个匹配字符串的括号,所以 posix-egrep 类型对我有用。
需要注意的是,-regextype 是 GNU find 的一个选项,而不是 BSD(至少不是 Mac BSD-like)find。如果此选项不可用,请务必安装 GNU find。如果在 Mac 上可以使用 brew 包 findutils。然后可通过 gfind 进行查找。
regextype posix-egrep 为我完成了这项任务。我认为默认是正则表达式 emacs。
posix-egrep 可以缩短为 egrep
y
yarian

从其他答案来看,这似乎是find的错。

但是,您可以这样做:

find . * | grep -P "[a-f0-9\-]{36}\.jpg"

您可能需要稍微调整一下 grep 并根据您的需要使用不同的选项,但它可以工作。


对我来说效果很好,并且在正则表达式方面提供了很大的自由度。
这样做的缺点是您无法利用 find-prune 功能,该功能将完全跳过某些目录。大多数情况下,这并不重要,但值得一提。
-prune 仍然可以工作,我猜。使用 -exec 会更危险 - 它会在所有文件上运行,而不仅仅是 grep 允许通过的文件。
find . * 等效于 find(更短的命令)。
S
Stan Kurdziel

在 Mac OS X 上(BSD 查找):效果与 the accepted answer 相同。

$ find -E . -regex ".*/[a-f0-9\-]{36}.jpg"

man find-E 使用扩展的正则表达式支持

注意:需要 .*/ 前缀来匹配完整路径:

出于比较目的,这里是 GNU/Linux 版本:

$ find . -regextype sed -regex ".*/[a-f0-9\-]\{36\}\.jpg"

似乎 -E 在 Ubuntu 上不可用(在 WSL Ubuntu 上测试)
@Clever Little Monkey - 不,接受的答案应该适用于 Ubuntu,这个变体专门针对 Mac OS X(或者可能是另一个 BSD 变体,如 FreeBSD)
-E 选项在 OpenBSD 版本的 find 上不可用
b
binbjz

简单的方法 - 您可以在开头指定 .* 因为 find 匹配整个路径。

$ find . -regextype egrep -regex '.*[a-f0-9\-]{36}\.jpg$'

查找版本

$ find --version
find (GNU findutils) 4.6.0
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
<http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION 
FTS(FTS_CWDFD) CBO(level=2)

您可以在开头指定 .* 因为 find 匹配整个路径。 这是一个非常棘手的好点。如果您在 dir/ 并使用此表示法搜索 samplefile.txt find . -regex 'samplefile.*' find 将不起作用
我确实更喜欢 egrep 而不是 sed - 所以谢谢
t
thiton

尝试使用单引号 (') 来避免您的字符串的外壳转义。请记住,表达式需要匹配整个路径,即需要看起来像:

 find . -regex '\./[a-f0-9-]*.jpg'

除此之外,我的 find (GNU 4.4.2) 似乎只知道基本的正则表达式,尤其是不知道 {36} 语法。我想你将不得不没有它。


j
jhoepken

使用正则表达式应用查找指令时,应使用绝对目录路径。在您的示例中,

find . -regex "[a-f0-9\-]\{36\}\.jpg"

应该改成

find . -regex "./[a-f0-9\-]\{36\}\.jpg"

在大多数 Linux 系统中,该系统无法识别正则表达式中的某些学科,因此您必须明确指出 -regexty 之类的

find . -regextype posix-extended -regex "[a-f0-9\-]\{36\}\.jpg"

M
Mark

如果您想保持跨平台兼容性,我找不到可以在不同版本的 find 中以一致的方式工作的内置正则表达式搜索选项。

与 grep 结合

正如@yarian 所建议的,您可以运行一个过度包含的查找,然后通过 grep 运行输出:

find . | grep -E '<POSIX regex>'

这可能会很慢,但如果您需要使用完整的正则表达式并且无法将搜索重新格式化为 glob,则会为您提供跨平台的正则表达式搜索

重写为 glob

-name 选项与提供有限(但跨平台)模式匹配的 glob 兼容。

您可以使用命令行中的所有模式,例如 * ? {} **。虽然不如完整的正则表达式强大,但您可以根据您的用例将搜索重新格式化为 glob。

互联网搜索 glob - 许多详细介绍完整功能的教程可在线获取


K
Kevin

我没有看到的一件事是如何将正则表达式与正则查找语法结合起来。

例如:我想在 BSD/Linux 上查找核心转储文件,我更改为我要扫描的根目录。例如:cd / 然后执行:

find \( -path "./dev" -o -path "./sys" -o -path "./proc" \) -prune -o -type f -regextype sed -regex ".*\.core$" -exec du -h {} \; 2> /dev/null

因此,在对剩余文件执行正则表达式之前,我使用 prune 命令排除多个系统目录。删除任何错误输出 (stderr)。

重要的部分是首先使用 Find 语法,然后使用正则表达式 OR (-o)。