使用bash,我需要查找0字节的文件,但在删除之前报告它们的存在



此问题的历史记录为:

我在NAS系统上有数百万个文件和目录。我发现了1095601个空(0字节)文件。这些文件曾经有数据,但由于前任未使用正确的工具集在XSAN和此Isilon NAS之间迁移数据而被销毁。

这些文件是媒体制作数据,如字体、PDF和图像文件。在它们存在的历史之外,它们不再有用。在我继续删除它们之前,生产用户需要记录哪些文件曾经存在,因此当他们浏览项目文件夹时,他们可以使用未受影响的文件,但可以引用同一目录中的文本文件,该文件记录了哪些文件曾经也在那里,从而提供了某些参考文件被破坏的原因。

那么,我如何在多个目录中找到文件并删除它们,但首先将它们的文件名输出到一个文本文件中,该文件将保存到每个相关的路径位置?

我的思路是:

for file in $(find . -type f -size 0); do
    echo "$file" >> /PATH/TO/FOUND/FILE/PARENT/DIR/deletedFiles.txt -print0 |
    xargs -0 rm ;
done

要删除每个空文件,同时留下一个名为deletedFiles.txt的文件,其中包含已删除文件的名称,请尝试:

PATH=/bin:/usr/bin find . -empty -type f -execdir bash -c 'printf "%sn" "$@" >>deletedFiles.txt' none {} + -delete

它的工作原理

  • PATH=/bin:/usr/bin

    这设置了一个临时但安全的路径。

  • find .

    这将启动find在当前目录中查找

  • -empty

    这个命令告诉find只查找空文件

  • -type f

    这限制了find只能查找常规文件。

  • -execdir bash -c 'printf "%sn" "$@" >>deletedFiles.txt' none {} +

    在每个包含空文件的目录中,这会将每个空文件的名称添加到文件deletedFiles.txt中。

    注意命令中none的特殊用法:

    bash -c 'printf "%sn" "$@" >>deletedFiles.txt' none {} +
    

    运行此命令时,bash将执行字符串printf "%sn" "$@" >>deletedFiles.txt,该字符串后面的参数将分配给位置参数:$0$1$2等。当我们使用$@时,它不包含$0。和往常一样,它扩展到$1$2。。。。因此,我们添加占位符none,以便占位符被分配为$0,我们将忽略它,并且文件名的完整列表被分配给"$@"

  • -delete

    这将删除每个空文件。

为什么不简单地

find . -type f -size 0 -exec rm -v + |
sed -e 's%^removed ../%%' -e 's/.$//' >deletedFiles.txt

如果您的find太旧,无法支持-exec ... +,则需要恢复到-exec rm -v {} ;或重构为

find . -type f -size 0 -print0 |
xargs -r -0 rm -v |
sed -e 's%^removed ../%%' -e 's/.$//' >deletedFiles.txt

简短的sed脚本是对rm -v的输出进行后处理,它看起来像

removed ‘./bar’
removed ‘./foo’

(文件名周围有一些有趣的引号)。当然,如果您对该输出很满意,只需从管道中省略sed脚本即可。

如果您事先知道哪些目录包含空文件,则可以在这些目录中单独运行上面的代码片段。假设您将上面的代码段保存为一个名为find-empty的脚本(具有适当的shebang和执行权限),您可以简单地使用

for path in /path/to/first /path/to/second/directory /path/to/etc; do
    cd "$path" && find-empty
done

只有当你有绝对路径时,这才会起作用(如果没有,你可以在子shell中添加括号来运行循环的主体)。

如果您想检查树中的所有目录,请将脚本更改为打印到标准输出(从脚本中删除>deletedFiles.txt),然后尝试类似的操作

find /path/to/tree -type d -exec sh -c '
    t=$(mktemp -t find-emptyXXXXXXXX)
    cd "$1" &&
      find-empty | grep . >"$t" &&
        mv "$t" deletedFiles.txt ||
        rm "$t"' _ {} ;

这使用了一个临时文件,以避免更新不包含任何空文件的目录的时间戳。grep .纯粹用于副作用;如果打印了任何(非空)行,它将返回成功,否则,它将报告失败;通过这种方式,我们知道是否将临时文件移动到目标目录。

在@JonathanLeffler的提示下,我成功地完成了以下操作:

#!/bin/bash
## call this script with: find . -type f -empty -exec handleEmpty.sh {} +
for file in "$@"
do
  file2="$(basename "$file")"
  echo "$file2" >> "$(dirname "$file")"/deletedFiles.txt
  rm "$file"
done

这意味着我在每个相应目录中的deletedFiles.txt标志文件中保留了已删除文件的跟踪,以便用户查看文件何时丢失。这样,他们就可以回到存档CD中检索这些被删除的文件,希望这些文件不是0字节的文件。

感谢@John1024建议使用empty标志而不是size

最新更新