查找名称中至​​少包含三个字符的所有 PDF

Abs*_*cDo 9 find

我想查找名称(不包括扩展名)大于三个的 PDF 文件。

$ find ~ -iregex ".{3,}/.pdf"
Run Code Online (Sandbox Code Playgroud)

什么都不返回,但是

$ find ~ -iregex ".+/.pdf"
Run Code Online (Sandbox Code Playgroud)

作品。

如何启用该{3,}变体?

Sté*_*las 20

这里使用标准通配符更容易:

find ~ -name '*???.[pP][dD][fF]'
Run Code Online (Sandbox Code Playgroud)

或者使用一些find实现(支持-regex也支持的实现-iname):

find ~ -iname '*???.pdf'
Run Code Online (Sandbox Code Playgroud)

对于任意数量的字符而不是3,您可能更愿意恢复到-iregex可用的位置(请参阅@Stephen Kitt 的回答),或者您可以使用zshksh93globs:

  • zsh

    set -o extendedglob # best in ~/.zshrc
    printf '%s\n' ~/**/?(#c3,).(#i)pdf(D)
    
    Run Code Online (Sandbox Code Playgroud)

    (D)考虑隐藏文件和隐藏目录中的文件,例如 with find

    • (#cx,y)zshregexp的通配符等价物{x,y}
    • (#i) 不区分大小写
    • ?任何单个字符的标准通配符(如 regexp .
    • **/: 任何级别的子目录(包括 0)
  • ksh93

    FIGNORE='@(.|..)' # to consider hidden files
    set -o globstar
    printf '%s\n' **/{3,}(?).~(i:pdf)
    
    Run Code Online (Sandbox Code Playgroud)
    • @(x|y): 类似于 regexp 的扩展 ksh 通配符运算符(x|y)
    • FIGNORE: 控制 glob 忽略哪些文件的特殊变量。设置后,通常会忽略隐藏文件,但我们仍然希望忽略存在的...目录条目。
    • {x,y}(z)ksh93的正则表达式的等效z{x,y}
    • ~(i:...): 不区分大小写的匹配。

Glob 在find这里有一些额外的优势,因为您可以获得一个排序列表(您可以zsh使用oNglob 限定符禁用该排序,或使用不同的排序标准),并且在文件名包含不形成有效字符的字节序列时也可以工作(例如例如,在使用 UTF-8 字符集的语言环境中,该find方法将无法报告 a $'St\xE9phane Chazelas - CV.pdf\xE9因为不是一个字符,与正则表达式.或通配符?*与 GNU不匹配find)。


Ste*_*itt 18

假设您使用的是 GNU find(您可能是,因为它-iregexPOSIXfind的 GNU 扩展),-regex并且-iregex默认使用 Emacs 正则表达式,它不识别{3,}. 您需要使用该-regextype选项指定不同类型的正则表达式;此外,您需要根据表达式与完整路径匹配的事实调整正则表达式:

find ~ -regextype posix-extended -iregex '.*/[^/]{3,}.pdf'
Run Code Online (Sandbox Code Playgroud)

您还应该对 进行转义.,使其与“.”匹配。而不是任何字符:

find ~ -regextype posix-extended -iregex '.*/[^/]{3,}\.pdf'
Run Code Online (Sandbox Code Playgroud)

正则表达式可以简化,因为我们只关心三个非“/”字符:

find ~ -regextype posix-extended -iregex '.*[^/]{3}\.pdf'
Run Code Online (Sandbox Code Playgroud)

为了完整起见,使用 FreeBSD 或 NetBSD find(另一个支持 的实现,-iregex虽然不是你的,但.+没有 就不能工作-E),你会写:

find ~ -iregex '.*[^/]\{3\}\.pdf'
Run Code Online (Sandbox Code Playgroud)

或者:

find -E ~ -iregex '.*[^/]{3}\.pdf'
Run Code Online (Sandbox Code Playgroud)

没有-E,这是基本的正则表达式(如 in grep)和-E 扩展的正则表达式(如 in grep -E)。

使用 ast-open 的find

find ~ -iregex '.*[^/]{3}\.pdf'
Run Code Online (Sandbox Code Playgroud)

(这是开箱即用的扩展正则表达式)。


Ric*_*ich 7

我怎么知道它们是 PDF?

除非你问,否则你不会。当然,我很迂腐,但你没有问他们名字中的文件.pdf。仅仅因为文件.pdf在文件名包含字符并不能使其成为 PDF 文件

事实上,让我们在这方面一直迂腐:如果文件名的最后四个字符是.pdf,那么的名称中总是多于三个字符

所以这样做是错误的,你可能会说:

$ find . -type f -name "*???.pdf"
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Setup_MagicISO.exe.pdf
Run Code Online (Sandbox Code Playgroud)

看到第二个了吗?它实际上是一个可执行文件。(我知道,我改了名字。)而且我还缺少一个我可以发誓在 Documents 目录中的 PDF ...

$ ls Documents
McLaren 720s Coupe:Order Summary.pdf
Pioneer Premier DEH-P490IB CD Install Manual.PDF
Setup_MagicISO.exe.pdf
Run Code Online (Sandbox Code Playgroud)

所以使用-iname我们可以找到那个,但它仍然打开了这个非 PDF 文件。

在这种情况下,我们真正想做的是使用命令检查文件的幻数file。一个选项输出MIME type,它更易于解析。然后find查询就变成了一个简单的-name "???*".

$ find . -type f -name "???*" -print0|xargs -0 file --mime
./.bash_history:                                              text/plain; charset=us-ascii
./.bash_logout:                                               text/plain; charset=us-ascii
./.bashrc:                                                    text/plain; charset=us-ascii
./.profile:                                                   text/plain; charset=us-ascii
./Documents/McLaren 720s Coupe:Order Summary.pdf:             application/pdf; charset=binary
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF: application/pdf; charset=binary
./Documents/Setup_MagicISO.exe.pdf:                           application/x-dosexec; charset=binary
./Downloads/Setup_MagicISO.exe:                               application/x-dosexec; charset=binary
./Downloads/WindowsUpdate.diagcab:                            application/vnd.ms-cab-compressed; charset=binary
Run Code Online (Sandbox Code Playgroud)

让我们使用冒号分隔符,并查找 MIME type application/pdf,然后将该部分清零并打印结果。请注意,我的一个文件的名称中有一个冒号;所以我不能只要求 awk ($2==":"){print $1}

$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF
Run Code Online (Sandbox Code Playgroud)

现在让我们通过设法包含名为aand 的PDF 文件来结束abc

$ mkdir Documents/other
$ cp -a Documents/McLaren\ 720s\ Coupe\:Order\ Summary.pdf Documents/other/a
$ cp -a Documents/Pioneer\ Premier\ DEH-P490IB\ CD\ Install\ Manual.PDF  Documents/other/abc
$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF
./Documents/other/abc
Run Code Online (Sandbox Code Playgroud)

就这样。我知道我可能会因为太迂腐而受到谴责,但在我的工作中有成千上万的 NFS 卷要搜索和各种名称不佳的文件,我希望更多的人会迂腐。

编辑添加:在现实世界中,我可能想利用updatedb来构建一个可搜索的文件索引,locate而不是find读取该索引,而parallel不是将xargs其串起来。不过,这有点超出了这个问题的范围。我也是板着脸写的。为什么我这么在意?我可能正在寻找电影和音频文件;或某些类型的照片;或项目数据目录中的二进制可执行文件。