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

使用bash,我需要查找0字节的文件,但在删除之前报告它们的存在,bash,find,Bash,Find,此问题的历史记录是: 我在NAS系统上有数百万个文件和目录。我发现有1095601个空(0字节)文件。这些文件过去包含数据,但被前一个未使用正确的工具集在XSAN和此Isilon NAS之间迁移数据的文件销毁 这些文件是媒体制作数据,如字体、PDF和图像文件。在它们存在的历史之外,它们不再有用。在我继续删除它们之前,生产用户需要记录哪些文件曾经存在,因此当他们浏览项目文件夹时,他们可以使用未受影响的文件,但随后引用同一目录中的文本文件,该目录记录了哪些文件曾经存在,从而提供了某些引用文件被破坏的

此问题的历史记录是:

我在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
为什么不简单

find . -type f -size 0 -exec rm -v + |
sed -e 's%^removed .\./%%' -e 's/.$//' >deletedFiles.txt
如果您的
查找
太旧,无法支持
-exec+
您需要恢复到
-execrm-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和execute权限),您只需使用

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.
纯粹用于副作用;如果打印任何(非空)行,将返回成功,否则将报告失败;这样,我们就知道是否将临时文件移动到目标目录。

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

PATH=/bin:/usr/bin find . -empty -type f -execdir bash -c 'printf "%s\n" "$@" >>deletedFiles.txt' none {} + -delete
工作原理
  • PATH=/bin:/usr/bin

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

  • 查找。

    这将开始查找当前目录中的
    find

  • -空的

    这告诉
    find
    只查找空文件

  • -类型f

    这将
    find
    限制为查找常规文件

  • -execdir bash-c'printf“%s\n”“$@”>>deletedFiles.txt'none{}+

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

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

    bash -c 'printf "%s\n" "$@" >>deletedFiles.txt' none {} +
    
    运行此命令时,
    bash
    将执行字符串
    printf“%s\n”$@>>deletedFiles.txt
    ,该字符串后面的参数将分配给位置参数:
    $0
    $1
    $2
    ,等等。使用
    $
    时,它不包括
    $0
    。它通常扩展为
    $1
    $2
    。。。。因此,我们添加了占位符
    none
    ,以便将占位符分配给
    $0
    ,我们将忽略该占位符,并将完整的文件名列表分配给
    “$@”

  • -删除

    这将删除每个空文件


在@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建议使用
标志而不是
大小

你真的需要更仔细地解释你需要做什么。看起来您需要查找大小为0的文件,对于每个这样的文件,将名称记录在找到该文件的目录中的
deletedFiles.txt
文件中,并删除该文件。您的
echo
命令将名称和
-print0
回显到一个文件名(可能不存在),然后运行
xargs
,而不进行任何输入,因为
echo
被发送到一个文件,因此
xargs
只运行
rm
,没有触发
rm
警告的参数。
-print0
可能属于
find
。如果是我的问题,我会使用
find-键入f-size 0-exec special-script.sh{}+
以生成名称列表和
special script.sh
将依次处理其每个参数,处理回显、文件名路径和删除(
对于“$@”中的文件;do echo“$file”>”$(dirname“$file”)/deletedFiles.txt;rm“$file”;done
或大约). 虽然这可能不需要两个脚本就可以完成,但对于像我这样懒散的人来说,这太像是一项艰苦的工作了。@JonathanLeffler我已经成功地完成了你的输入。谢谢。如果不是因为
-print0
,你也可以在管道中使用
tee
。我尝试了你的第二种选择