使用 find 删除包含文件的目录

使用 find 删除包含文件的目录

我正在目录列表中搜索某些文件,并且我想删除该文件所在的目录。

这就是我正在尝试的:

find /converter/storage/unmatched/ -size -4b -name '*.mp3' -execdir mv -b `dirname {}` /converter/storage/smallfiles/ \;
mv: cannot move `.' to `/converter/storage/smallfiles/.'

我首先尝试移动它,只是为了向自己证明这可以在不丢弃非预期文件的情况下完成。如何移动或删除包含目录?

答案1

由于以下几个原因,您的命令将无法按预期工作:

  1. bash 评估​`dirname {}`​ find 命令被执行。

    dirname可以通过调用 bash 来评估命令的输出来解决此问题

  2. -execdir执行命令之前对找到的文件目录的更改。

    因此,即使使用正确的语法,也dirname {}始终是.

  3. 由于 find 会遍历所有目录内的所有文件(而不是目录本身),因此移动当前正在处理的目录可能会导致意外行为。

    我不太清楚如何详细说明,但下面的例子应该可以说明这一点。

    $ find data -type f -printf "  %p" ; echo
      data/1/b  data/1/a  data/2/b  data/2/a
    $
    $ find data -type f -exec bash -c ' \
    > echo -n "  "mv `dirname {}` backup/
    > ' \; ; echo
      mv data/1 backup/  mv data/1 backup/  mv data/2 backup/  mv data/2 backup/
    $
    $ find data -type f -exec bash -c '
    > echo -n "  "mv `dirname {}` backup/; mv `dirname "{}"` backup/
    > ' \; ; echo
      mv data/1 backup/  mv data/1 backup/
    mv: cannot stat `data/1': No such file or directory
    

    移动目录 后data/1, find 继续处理其内容。这会导致出现错误消息,因为 findmv会对 中的每个文件执行data/1,但除此之外运行正常。当它完成处理 时data/1, find 不知何故“丢失”了。

  4. 虽然 find 可以正确处理所有可能具有特殊含义的字符(如果{}作为 find 的普通参数出现),但如果路径中出现空格,则示例 3 中的命令将无法正确执行。为了避免这种情况,dirname必须将的参数输出都用引号引起来。

    使用mv "`dirname "{}"`"(或mv "$("{}")",更易于辨认)可以很好地处理空格,但通常会导致灾难性的后果1

  5. mv -b无法备份目录,只能备份文件。

正如你自己发现的,问题 3 只会在你尝试移动目录,但如果您删除它则不会。因此,问题 3(在此过程中修复问题 5)的一个简单而安全的解决方案是将匹配的目录移动到 zip 文件中。2

{}问题 4 可以通过将其作为参数传递给 bash 并以 方式访问来解决$0

命令

find /converter/storage/unmatched/ -type f -size -4b -name '*.mp3' \ -exec bash -c ' \
  zip -0mqr smallfiles.zip "$(dirname "$0")"\
' {} \;

将按预期工作,尽管在尝试多次移动目录时仍会生成错误消息。

一种更干净的方法(即没有错误消息)是find -depth -type d浏览目录本身。3

对于每个目录,我们可以使用

find "$0" -maxdepth 1 -type f -size -4b -name '*.mp3' -printf 1 -quit

打印1当且仅当应该删除它时4,并测试([)以检查是否找到打印1

命令

find /converter/storage/unmatched/ -depth -type d -exec bash -c ' \
  [ $(find "$0" -maxdepth 1 -type f -size -4b -name '*.mp3' -printf 1 -quit) ] \
  && echo zip -0mqr smallfiles.zip "$0"\
  ' {} \;

才会达到预期的效果。


1如果目录名称无与伦比例如,由一个换行符组成,"$(dirname "{}")"将计算为unmatched并将$(dirname {})计算为.(即,您从中执行命令的文件夹)!

2如果文件很大,即使不压缩文件,这也比直接移动文件花费的时间要长得多。由于目标文件夹名为小文件,我认为这不会是个问题。

3 -depth` 开关使 find 在处理目录本身之前先处理每个目录的内容。这避免了我们在使用第一种方法时收到的错误消息。

4开关-quit使查找在找到第一个匹配项后停止。这不是绝对必要的,但它可能会加快一点速度。

相关内容