Answers:
假设您使用的是GNU find
(由于-iregex
是POSIXfind
的GNU扩展,所以您可能正在使用),-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'
(即开即用的扩展正则表达式)。
在这里,使用标准通配符会更容易:
find ~ -name '*???.[pP][dD][fF]'
或使用某些find
实现(那些-regex
也支持的实现-iname
):
find ~ -iname '*???.pdf'
对于任意数量的字符而不是3
,您可能希望将其恢复为-iregex
可用的位置(请参阅@Stephen Kitt的答案),也可以使用zsh
或ksh93
glob:
zsh
:
set -o extendedglob # best in ~/.zshrc
printf '%s\n' ~/**/?(#c3,).(#i)pdf(D)
(与(D)
一起考虑隐藏文件和隐藏目录中的文件find
)
(#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)
:扩展的ksh通配符运算符,类似于regexp (x|y)
。FIGNORE
:特殊变量,用于控制全局文件忽略哪些文件。设置后,通常不会忽略隐藏文件,但是我们仍然希望忽略存在的.
和..
目录条目。{x,y}(z)
是ksh93
的正则表达式的等效z{x,y}
。~(i:...)
:不区分大小写的匹配。Globs在find
这里具有一些额外的优势,因为您可以获得一个排序列表(可以zsh
使用oN
glob限定符禁用该排序,或者使用其他排序标准),并且在文件名包含不构成有效字符的字节序列时(例如例如,在使用UTF-8字符集的语言环境中,该find
方法将无法报告a $'St\xE9phane Chazelas - CV.pdf
,\xE9
因为不是一个字符与regexp .
或通配符?
或*
GNU 都不匹配find
。
shopt -s dotglob globstar; printf '%s\n' ~/**/*???.[pP][dD][fF]
除非你问,否则你不会。当然,我正在做书,但是您没有询问名称中带有的文件.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
进行线程化。不过,这超出了这个问题的范围。我也是用笔直的脸写的。我为什么这么在乎呢?我可能正在寻找电影和音频文件;或某些类型的照片;或项目数据目录中的二进制可执行文件。
.pdf
,那么您的学步将不胜感激。但这是一个相对不寻常的情况(尽管您的工作是这样),我们没有任何理由相信提问者实际上必须处理该问题,因此,我确实认为您提出的观点虽然有效,但会分散您的注意力-我认为您所说的有力方式将答案推到“(可能)无用”的境界。(当然,仅是我的意见。)