突出显示一个文件夹中的多个 PDF

突出显示一个文件夹中的多个 PDF

我需要在文件夹结构中找到每个包含多个 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-HiRes2Tomato.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以 确保 位于目录名中,因此我们找不到名为 的文件。-iregexHiRes.pdf/HiResabcHiRes123.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 功夫,但从那里很容易就找到了答案。我的建议是研究这个场景和答案,并将其应用于你手头的情况。然后,把它拆开。了解每个命令的作用、为什么参数以这种方式陈述以及它们产生的输出是什么。了解为什么将它们连接在一起会产生这样的行为。这将使你在系统管理职业生涯中走得更远。

相关内容