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

419
我有一些以生成的uuid1字符串命名的图片。例如81397018-b84a-11e0-9d2a-001b77dc0bed.jpg。我想使用"find"命令找到所有这些图片。
find . -regex "[a-f0-9\-]\{36\}\.jpg".

但它不工作。正则表达式有问题吗?


13
也许需要更改正则表达式的类型。默认值是“Emacs 正则表达式”,不知其意。 - pavium
https://dev59.com/6m035IYBdhLWcg3wE71s - Steve Claridge
9个回答

473
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:
$ 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'.

4
@Tom,这是 find 命令中正则表达式的工作方式。根据手册,正则表达式匹配整个文件路径,包括目录,这意味着你的正则表达式周围有一个隐含的 "^...$"。它必须匹配整行结果。 - Manny D
3
我认为在.*/中不需要/,因为.*可以匹配零个或多个(几乎)任何字符。 - Jeff
3
对于那些(像我一样)第一次没有正确阅读正则表达式的人,请注意在特殊正则表达式字符前面加上反斜杠,例如:\{36\} - Lucas Wilson-Richter
20
我在寻找正则表达式类型的完整列表时遇到了困难(manpage已经过时):有效类型包括“findutils-default”、“awk”、“egrep”、“ed”、“emacs”、“gnu-awk”、“grep”、“posix-awk”、“posix-basic”、“posix-egrep”、“posix-extended”、“posix-minimal-basic”和“sed”。 - Noah Sussman
14
一定要在-regex标志之前放置-regextype标志,否则它将无效! - Christopher Orr
显示剩余11条评论

123
-regex查找表达式匹配整个名称,包括相对于当前目录的路径。 对于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 find的,我不知道BSD版本的find,它也是Mac上的默认版本。)


3
我的正则表达式中有多个匹配字符串,所以使用“posix-egrep”类型对我很有用。 - palswim
4
需要注意的是,-regextype 是 GNU find 的选项,而非 BSD(至少不是类似于 Mac 的 BSD)find。如果该选项不可用,请确保安装 GNU find。如果使用 Mac,则可以通过 brew 包 findutils 进行安装。之后,可以通过 gfind 使用 find。 - DanCat
regextype posix-egrep 对我来说已经完成了任务。我认为默认的是 regextype emacs。 - infoclogged
2
posix-egrep can be shortened to just egrep - bloody

54

从其他答案来看,这似乎是find命令的问题。

但是,您可以使用以下方式代替:

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

您可能需要微调grep并根据您想要的内容使用不同的选项,但它可以工作。


对我来说运行良好,并且在正则表达式方面提供了很大的自由度。 - glaucon
3
使用这种方法的一个弊端是,您无法利用 find-prune 功能,该功能将完全跳过某些目录。大多数情况下,这并不是很重要,但值得一提。 - Alexander Bird
“-prune” 仍然可以工作,我猜。使用“-exec”会更危险,它将在所有文件上运行,而不仅仅是 grep 允许通过的文件。 - tpb261
2
"find . *" 是等同于 "find" 的缩写命令。 - bloody
1
谢谢!我对find命令的正则表达式语法一直感到困惑,但这个方法解决了我的问题。 - uzluisf

31

在 Mac OS X 上(使用 BSD find):与被接受的回答产生相同的效果。

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

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

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

为了比较,这里是GNU/Linux版本:

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

4
似乎在Ubuntu上(在WSL Ubuntu上测试过)没有可用的“-E”选项。 - Elliott Beach
2
@Clever Little Monkey - 不,被接受的答案应该在Ubuntu上可行,这个变体是专门为Mac OS X(或者可能是其他BSD变体,如FreeBSD)设计的。 - Stan Kurdziel
OpenBSD版本的find命令中不支持“-E”选项。 - moo

15
尝试使用单引号(')来避免字符串的shell转义。请记住,表达式需要与整个路径匹配,即需要看起来像:
find . -regex '\./[a-f0-9-]*.jpg'

除此之外,看起来我的发现(GNU 4.4.2)只知道基本的正则表达式,尤其不了解{36}这种语法。我想你可能需要在没有它的情况下应付一下。

15
简单的方法 - 你可以在开头指定.*,因为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 将无法工作。 - Elcid
我更喜欢使用egrep而不是sed - 所以谢谢。 - dotnetCarpenter

11
你在应用正则表达式的查找指令时应该使用绝对目录路径。 在你的示例中,
find . -regex "[a-f0-9\-]\{36\}\.jpg"

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

在大多数Linux系统中,某些正则表达式的规则无法被该系统识别,因此您必须明确指出使用“-regextype”来指定。
find . -regextype posix-extended -regex "[a-f0-9\-]\{36\}\.jpg"

1

有一件事我没有看到涵盖,那就是如何将正则表达式与常规查找语法结合起来。

例如:我想在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

所以我正在使用修剪命令来排除多个系统目录,然后对剩余的文件进行正则表达式操作。任何错误输出(stderr)都将被删除。

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


1

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

与grep结合使用

  1. 如@yarian所建议的那样,您可以运行一个过度包容的find,然后通过grep运行输出:

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

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

重写为glob

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

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

互联网搜索globs - 许多详细功能的教程都可以在线获得。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接