使用find查找某个目录并删除其中除一个目录外的所有文件

使用find查找某个目录并删除其中除一个目录外的所有文件

我遇到以下问题。我有一个目录结构,想要删除名为 的目录中的所有内容Caches。除所有名为的目录外,所有内容都应删除Snapshots。我不知道如何做到这一点寻找或我知道的任何其他命令。

我问的原因是:在 iOS 上,每个应用程序都有自己的 Caches 目录。这些有时无法正确清除,具体取决于应用程序。有了这个答案的解决方案,当设备的驱动器安装在另一台计算机上时,例如使用 FUSE (iExplorer),人们将能够清除 iOS 上的缓存,从而优化磁盘空间。

这是我到目前为止所拥有的:

find . 2>/dev/null -type d -name "Caches" -maxdepth 3 -print

这会返回类似以下内容的内容:

./Library/Caches

当我执行 a 时,ls ./Library/Caches我会看到所有内容和Snapshots目录,我想排除它们,因为最终我想要-delete除此之外的所有内容。


我想要这样的东西:

  Before:                            After:

  .                                  .
  ├── a                              ├── a
  │   ├── a                          │   ├── a
  │   └── Caches                     │   └── Caches
  │       ├── a                      │       └── a
  │       │   └── Snapshots          │           └── Snapshots
  │       │       └── a              │               └── a
  │       ├── b                      └── b
  │       │   └── a                      └── c
  │       └── c                  
  └── b
      ├── c
      └── Caches
          ├── a
          │   └── foo
          │       └── a
          └── b
              └── a

答案1

我对问题的措辞有点困惑。如果您想要删除目录中./Library/Caches除名为 的单个文件夹之外的所有内容Snapshots,则无需使用find.在 中bash,shell glob 是最简单的方法:

shopt -s extglob  # probably already enabled
echo Library/Caches/!(Snapshots)

如果这会打印您要删除的所有文件/目录,则替换echorm -f --.

如果您想要保留Snapshots目录树中不同级别的多个目录,那么使用 GNU您可以执行以下操作:./Library/Cachesfind

find Library/Caches ! -path '*Snapshots*'

这应该打印所有文件/目录,不包括Snapshots 路径中的文件/目录。它将包含包含目录(或其子目录包含)的目录Snapshots,但find ... -delete不会删除这些目录,而是打印一条错误,指出它们不为空。一旦你感到高兴,就添加-delete到最后。

需要注意的是,这将留下任何文件命名Snapshots完好。如果这是一个问题,请改为:

find Library/Caches \( ! -path '*Snapshots*' -o -type f -name Snapshots \)

高兴的时候再补充-delete

答案2

find . -depth -print0 | perl -0lne '
  if ("$_/" =~ m{/Caches(/.*)}s && $1 !~ m{/Snapshots/}) {rmdir $_ or unlink $_}'

如果你find不支持-print0,你可以用 替换它-exec printf '%s\0' {} +

这个想法是打印以 NUL 结尾的文件列表(因为 0 是文件路径中唯一不能出现的字节)并使用perl带有选项-n-0为每个文件名运行一些代码($_设置为文件名)。

使用 时-depth,文件将在其父目录之前打印。如果文件或目录depth的路径/Caches/后面不包含/Snapshosts/.

答案3

我不是find巫师,所以我不想说你不能用 来做到这一点find,但我确实知道可以用几行 来完成bash。鉴于我正确理解您的目录结构:

#!/bin/bash

for i in Library/Caches/*; do
    if [[ -d "$i" ]]; then
         [[ "$i" =~ "Snapshots" ]] ||  echo "rm-ing  $i" # change to rm -rf "$i" to use
    fi
done

for语句返回 中的每个项目Library/Caches/。该if [[ -d "$i" ]]语句检查每个项目是否是一个目录,如果是,则检查它的名称以查看它是否包含“Snapshots” [[ "$i" =~ "Snapshots" ]]。因为没有运算符可以否定正则表达式匹配,例如!=~,所以我过去常常在上一个命令不成功时||执行rm,例如目录名称不包含快照。

这将在任何使用的现代系统上运行bash,但它必须有bash。另外,您可能需要尝试一下目录结构,但这应该适合您。

答案4

第一部分:找到名为caches的目录并对它们执行一些操作

find . -name Caches -type d -exec … \;

第二部分:遍历缓存目录,并删除所有内容,但保留Snapshots子目录及其内容(以及通向它们的路径)。进行深度优先遍历,这样目录一旦变空就可以删除。

    find /path/to/Caches -depth -name Snapshots -type d -prune \
                             -o \( -type d -empty -o ! -type d \) -delete

现在将它们组合在一起。

find . -name Caches -type d -exec
    find {} -depth -name Snapshots -type d -prune \
                -o \( -type d -empty -o ! -type d \) -delete

相关内容