我需要在文件夹结构中找到每个包含多个 PDF 的文件夹,但隐藏令人讨厌的隐藏文件,例如.HResource
渗透到我们的文件系统的文件。
我只想过滤文件名中包含 HiRes 的文件夹。
理想情况下,我想在顶层运行它,以便它搜索每个具有 HiRes 的文件夹并吐出其中包含多个 PDF 的文件夹。
操作系统是 RHEL 7,可以根据需要以用户/root 身份运行此命令。
我玩过
find -type f -iname '*.pdf' -iname '*HiRes*' ! -iname '.*' -printf '%h\n' | sort | uniq -d
但到目前为止,运气不佳,因为隐藏文件不断显示,因此在 11,000 个文件夹系统中出现数千个误报。例如,给定以下目录结构,
.
|--Apples.HiRes1
| |--Gala.pdf
| |--Granny Smith.pdf
| |--McIntosh.pdf
| |--Red Delicious.pdf
|--Banana-HiRes2
| |--upper.pdf
| |--subdir
| | |--lower.pdf
|--Cherry_HiRes3
| |--Bing.pdf
| |--Blossom.jpg
| |--.pesky
| |--.hidden
| |--.files
| |--.HResource
|--Dates (HiRes4)
| |--Midsummer.Pdf
| |--New Year’s Eve.PDF
|--Employees
| |--Fred.pdf
| |--Ginger.pdf
| |--New Hires
| | |--Sam Malone.pdf
| | |--Woody Boyd.pdf
|--Gemstones
| |--Rubies
| | |--1.pdf
| | |--2.pdf
| |--Sapphires
| | |--3.pdf
| | |--4.pdf
|--Tomato.HiRes
| |--Bacon
| |--Lettuce
| | |--5.pdf
| | |--6.pdf
|--Zucchini.LoRes
| |--Bread.pdf
| |--Squash.pdf
输出应该是
./Apples.HiRes1
./Dates (HiRes4)
注意
Cherry_HiRes3
被排除,因为它只有一个 PDF 文件。Banana-HiRes2
Tomato.HiRes
因为它们有两个 PDF 文件而 被排除在下面他们,但不是在他们。Zucchini.LoRes
被排除(显然),因为它的名称有LoRes
而不是HiRes
。
答案1
与您尝试过的解决方案接近的解决方案是
find . -ipath '*HiRes*/*.pdf' -printf '%h\n' | sort | uniq -d
正如您(至少部分)理解的那样,-name
和 -iname
测试仅对一个进行操作文件名;
即,只有一层路径名。因此,当您说 时-iname '*.pdf' -iname '*HiRes*'
,这相当于-iname '*HiRes*.pdf'
;即,您正在寻找名称同时匹配*.pdf
和 的文件*HiRes*
。但是-path
,-ipath
和测试对整个路径进行操作,因此这将列出路径名包含并以 结尾的 文件。我们在它们之间放置-regex
以 确保 位于目录名中,因此我们找不到名为 的文件。-iregex
HiRes
.pdf
/
HiRes
abcHiRes123.pdf
我们可以用
find . -iregex '.*HiRes.*/.*\.pdf' -printf '%h\n' | sort | uniq –d
请注意 glob 语法(由 所用)和正则表达式语法之间的区别 -ipath
。点 (.
) 表示任何字符,因此我们需要使用.*
来匹配“任何内容”,并 \.
匹配文字.
。
以上两种方法都会找到Tomato.HiRes
问题示例中的目录,因为 .
匹配 /
,所以.*/.*
匹配/Lettuce/5
,所以.*HiRes.*/.*\.pdf
匹配 ./Tomato.HiRes/Lettuce/5.pdf
。如果你同意,那就太好了。但是,如果你只想计算以下 PDF 文件:在目录 *HiRes
,使用
find . -iregex '.*HiRes[^/]*/[^/]*\.pdf' -printf '%h\n' | sort | uniq -d
我们用它来[^/]
匹配除 之外的任何字符/
。
一个完全不同的方法,可能更容易理解,是
find . -iname '*HiRes*' -type d -exec sh -c \
'shopt -s nocaseglob; for dir do files=("$dir"/*.pdf);
if [ "${#files[@]}" -gt 1 ]; then echo "$dir"; fi; done' sh {} +
这仅用于find
查找名为 的目录*HiRes*
。然后它将这些目录名称转换为一个简短的 shell 脚本,该脚本使用 glob 枚举每个目录中的所有 PDF 文件并对其进行计数。
答案2
编辑:这实际上也不起作用。请参阅下面的评论。
您是否尝试过添加-not -iname '.*'
命令find
?!
可能没有按照您的想法执行。
这将导致find -type f -iname '*.pdf' -iname 'HiRes' -not -iname '.*' -printf '%h\n' | sort | uniq -d
答案3
好的,在意识到我之前的答案是错误的之后,我又尝试了一次。JandP,你离正确的命令已经很近了。
设置
- 10 个目录,1-10,以下
$s
简称 $n
每个目录中的文件,其中$n
是目录编号,名为$s-$n.pdf
$n
每个里面都有点文件,.fake-$s-$n.pdf
我用来创建此文件树的命令:
for s in `seq 1 10`; do mkdir $s; cd $s; for n in `seq 1 $s`; do touch $s-$n.pdf; touch .fake-$s-$n.pdf; done; cd ..; done
产生了这棵树:
.
├── 1
│ ├── 1-1.pdf
│ └── .fake-1-1.pdf
├── 10
│ ├── 10-10.pdf
│ ├── 10-1.pdf
│ ├── 10-2.pdf
│ ├── 10-3.pdf
│ ├── 10-4.pdf
│ ├── 10-5.pdf
│ ├── 10-6.pdf
│ ├── 10-7.pdf
│ ├── 10-8.pdf
│ ├── 10-9.pdf
│ ├── .fake-10-10.pdf
│ ├── .fake-10-1.pdf
│ ├── .fake-10-2.pdf
│ ├── .fake-10-3.pdf
│ ├── .fake-10-4.pdf
│ ├── .fake-10-5.pdf
│ ├── .fake-10-6.pdf
│ ├── .fake-10-7.pdf
│ ├── .fake-10-8.pdf
│ └── .fake-10-9.pdf
├── 2
│ ├── 2-1.pdf
│ ├── 2-2.pdf
│ ├── .fake-2-1.pdf
│ └── .fake-2-2.pdf
├── 3
│ ├── 3-1.pdf
│ ├── 3-2.pdf
│ ├── 3-3.pdf
│ ├── .fake-3-1.pdf
│ ├── .fake-3-2.pdf
│ └── .fake-3-3.pdf
├── 4
│ ├── 4-1.pdf
│ ├── 4-2.pdf
│ ├── 4-3.pdf
│ ├── 4-4.pdf
│ ├── .fake-4-1.pdf
│ ├── .fake-4-2.pdf
│ ├── .fake-4-3.pdf
│ └── .fake-4-4.pdf
├── 5
│ ├── 5-1.pdf
│ ├── 5-2.pdf
│ ├── 5-3.pdf
│ ├── 5-4.pdf
│ ├── 5-5.pdf
│ ├── .fake-5-1.pdf
│ ├── .fake-5-2.pdf
│ ├── .fake-5-3.pdf
│ ├── .fake-5-4.pdf
│ └── .fake-5-5.pdf
├── 6
│ ├── 6-1.pdf
│ ├── 6-2.pdf
│ ├── 6-3.pdf
│ ├── 6-4.pdf
│ ├── 6-5.pdf
│ ├── 6-6.pdf
│ ├── .fake-6-1.pdf
│ ├── .fake-6-2.pdf
│ ├── .fake-6-3.pdf
│ ├── .fake-6-4.pdf
│ ├── .fake-6-5.pdf
│ └── .fake-6-6.pdf
├── 7
│ ├── 7-1.pdf
│ ├── 7-2.pdf
│ ├── 7-3.pdf
│ ├── 7-4.pdf
│ ├── 7-5.pdf
│ ├── 7-6.pdf
│ ├── 7-7.pdf
│ ├── .fake-7-1.pdf
│ ├── .fake-7-2.pdf
│ ├── .fake-7-3.pdf
│ ├── .fake-7-4.pdf
│ ├── .fake-7-5.pdf
│ ├── .fake-7-6.pdf
│ └── .fake-7-7.pdf
├── 8
│ ├── 8-1.pdf
│ ├── 8-2.pdf
│ ├── 8-3.pdf
│ ├── 8-4.pdf
│ ├── 8-5.pdf
│ ├── 8-6.pdf
│ ├── 8-7.pdf
│ ├── 8-8.pdf
│ ├── .fake-8-1.pdf
│ ├── .fake-8-2.pdf
│ ├── .fake-8-3.pdf
│ ├── .fake-8-4.pdf
│ ├── .fake-8-5.pdf
│ ├── .fake-8-6.pdf
│ ├── .fake-8-7.pdf
│ └── .fake-8-8.pdf
└── 9
├── 9-1.pdf
├── 9-2.pdf
├── 9-3.pdf
├── 9-4.pdf
├── 9-5.pdf
├── 9-6.pdf
├── 9-7.pdf
├── 9-8.pdf
├── 9-9.pdf
├── .fake-9-1.pdf
├── .fake-9-2.pdf
├── .fake-9-3.pdf
├── .fake-9-4.pdf
├── .fake-9-5.pdf
├── .fake-9-6.pdf
├── .fake-9-7.pdf
├── .fake-9-8.pdf
└── .fake-9-9.pdf
10 directories, 110 files
查找
使用 JandP 的基本find
命令,以及我在另一个(错误)答案的评论中透露的知识,产生了一个输出,显示每个目录中匹配文件的数量,排除任何点文件:
$ find -type f -iname '*.pdf' ! -iname '.*' -printf '%h\n' | sort | uniq -c
1 ./1
10 ./10
2 ./2
3 ./3
4 ./4
5 ./5
6 ./6
7 ./7
8 ./8
9 ./9
awk
最后进行了一个简单的比较,产生了预期的结果:
$ find -type f -iname '*.pdf' ! -iname '.*' -printf '%h\n' | sort | uniq -c | awk '$1 > 1'
10 ./10
2 ./2
3 ./3
4 ./4
5 ./5
6 ./6
7 ./7
8 ./8
9 ./9
结论
JandP 非常接近答案。这个答案需要一点 Google 功夫,但从那里很容易就找到了答案。我的建议是研究这个场景和答案,并将其应用于你手头的情况。然后,把它拆开。了解每个命令的作用、为什么参数以这种方式陈述以及它们产生的输出是什么。了解为什么将它们连接在一起会产生这样的行为。这将使你在系统管理职业生涯中走得更远。