我想找到名称(不包括扩展名)大于3的PDF文件。
$ find ~ -iregex ".{3,}/.pdf"
什么都不返回,但是
$ find ~ -iregex ".+/.pdf"
作品。
如何启用该{3,}
变体?
答案1
这里使用标准通配符更容易:
find ~ -name '*???.[pP][dD][fF]'
或者通过一些find
实现(那些支持的-regex
也支持-iname
):
find ~ -iname '*???.pdf'
对于任意数量的字符而不是3
,您可能更愿意恢复到-iregex
可用的位置(请参阅@斯蒂芬·基特的回答) 或者你可以使用zsh
or ksh93
glob:
zsh
:set -o extendedglob # best in ~/.zshrc printf '%s\n' ~/**/?(#c3,).(#i)pdf(D)
(
(D)
考虑隐藏文件和隐藏目录中的文件,例如 withfind
)(#cx,y)
是zsh
正则表达式的通配符等价物{x,y}
(#i)
对于不区分大小写的?
任何单个字符的标准通配符(如 regexp.
)**/
:任意级子目录(包括0级)
ksh93
:FIGNORE='@(.|..)' # to consider hidden files set -o globstar printf '%s\n' **/{3,}(?).~(i:pdf)
@(x|y)
: 类似于 regexp 的扩展 ksh 通配符运算符(x|y)
。FIGNORE
:控制全局忽略哪些文件的特殊变量。设置后,通常会忽略隐藏文件,但我们仍然希望忽略存在的目录条目.
。..
{x,y}(z)
isksh93
相当于 regexpz{x,y}
。~(i:...)
: 不区分大小写的匹配。
Glob 在这里有一些额外的优点,因为您可以获得一个排序列表(您可以使用glob 限定符find
禁用排序,或使用不同的排序标准),并且当文件名包含不形成有效字符的字节序列时也可以工作(例如例如,在使用 UTF-8 字符集的语言环境中,该方法将无法报告 a ,因为不是字符,因此与 regexp或通配符或GNU不匹配。zsh
oN
find
$'St\xE9phane Chazelas - CV.pdf
\xE9
.
?
*
find
答案2
假设你正在使用 GNU find
(你可能就是这样,因为它-iregex
是 GNU 的扩展)POSIXfind
),-regex
并且-iregex
默认为 Emacs 正则表达式,它不识别{3,}
.您需要使用该-regextype
选项指定不同类型的正则表达式;此外,您需要调整正则表达式以使其与完整路径匹配:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}.pdf'
您还应该转义.
以便它与“.”匹配。而不是任何字符:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}\.pdf'
正则表达式可以简化,因为我们只关心三个非“/”字符:
find ~ -regextype posix-extended -iregex '.*[^/]{3}\.pdf'
为了完整起见,对于 FreeBSD 或 NetBSD find
(另一种支持 的实现-iregex
,不是你的,但如果.+
没有 就无法工作-E
),你可以这样写:
find ~ -iregex '.*[^/]\{3\}\.pdf'
或者:
find -E ~ -iregex '.*[^/]{3}\.pdf'
没有-E
,那就是基本正则表达式(如grep
)并与-E
扩展正则表达式(像grep -E
)。
使用 ast-open 的find
:
find ~ -iregex '.*[^/]{3}\.pdf'
(这是开箱即用的扩展正则表达式)。
答案3
我怎么知道它们是 PDF?
除非你问,否则你不会。当然,我很迂腐,但你没有问文件.pdf
名中带有。仅仅因为文件具有.pdf
文件名中的字符不使其成为 PDF 文件。
事实上,让我们对此一直迂腐一点:如果文件名的最后四个字符是.pdf
,那么它的名称中始终包含三个以上的字符。
所以这样做错误的方法,你可能会说:
$ find . -type f -name "*???.pdf"
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Setup_MagicISO.exe.pdf
看到第二个了吗?它实际上是一个可执行文件。 (我知道,我改了名字。)而且我还丢失了一个 PDF 文件可以宣誓位于文档目录中...
$ ls Documents
McLaren 720s Coupe:Order Summary.pdf
Pioneer Premier DEH-P490IB CD Install Manual.PDF
Setup_MagicISO.exe.pdf
因此,-iname
我们可以找到该文件,但仍然会出现这个非 PDF 文件。
我们真的在这种情况下要做的是检查文件的幻数使用file
命令。一个选项输出MIME类型,这样解析起来更简单。然后查询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
让我们使用冒号分隔符,并查找 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
a
现在,让我们通过设法包含名为和 的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
就这样。我知道我可能会因为过于迂腐而受到批评,但是在我的工作中面对数以千计的 NFS 卷和各种命名不当的文件,我希望更多的人会迂腐。
编辑添加:在现实世界中,我可能想利用它来updatedb
构建可搜索的文件索引,locate
而不是find
读取该索引,而parallel
不是xargs
线程化。但这有点超出了这个问题的范围。我也是板着脸写的。我为什么这么关心?我可能正在寻找电影和音频文件;或某些类型的照片;或项目数据目录中的二进制可执行文件。