获取 find 输出检索到的文件的确切大小

获取 find 输出检索到的文件的确切大小

我的 shell 引擎是忙碌盒1.31.0或者bash 3.2

我需要获取从中检索到的文件的大小寻找命令。

我一直在尝试仅查找 60 多天前修改过的文件,同时获取所有这些文件的大小(最好以 MB 表示法的一行进行汇总)。这是我尝试过的。

find -type f -mtime +60 -print0 | xargs -0 du -smc

find -type f -mtime +60 -exec du -smc {} \;

前者逐行检索所有超过 60 天的文件(直到这里才出现问题),但它奇怪地多次计算所有这些行之间的大小,在最后一行我得到一个不对应的“总”大小到输出的实际总大小。它看起来是这样的。

.....
.....
0       ./FOLDER 2018/Copy #183 of ~$DATABASE OTHERS - NOV.18N.xlsx
42      ./FOLDER 2018/F9C8A618.tmp
0       ./FOLDER 2018/Copy #166 of ~$DATABASE PORTFOLIO NOV.18.xlsx
3275    total
10      ./FOLDER 2018/CFDC6981.tmp
2       ./FOLDER 2018/D5AAF4EB.tmp
0       ./LIFE INSURANCE/Copy #15 of ~$Copy of LIFE INSURANCE CLIENTS.xlsx
12      total

后者的输出逐行计算每个重合文件的大小,但不计算总数。

我期待的是:

    0       ./FOLDER 2018/Copy #183 of ~$DATABASE OTHERS - NOV.18N.xlsx
    42      ./FOLDER 2018/F9C8A618.tmp
    0       ./FOLDER 2018/Copy #166 of ~$DATABASE PORTFOLIO NOV.18.xlsx
    10      ./FOLDER 2018/CFDC6981.tmp
    2       ./FOLDER 2018/D5AAF4EB.tmp
    0       ./LIFE INSURANCE/Copy #15 of ~$Copy of LIFE INSURANCE CLIENTS.xlsx
    54      total

或者只是没有所有线条的实际尺寸结果

54      total

任何帮助都会受到好评。

答案1

find尝试通过管道传输to的输出du并指定--files0-from -标志:

find -type f -mtime +60 -print0 | du -shc --files0-from -

最后应该会给你一个总计

要获得总数,请将输出通过管道传输到tail -n1

find -type f -mtime +60 -print0 | du -shc --files0-from - | tail -n1

我应该提到的是,我实际上只是使用 gnu linux 测试了这个,而不是 busybox。看着忙碌盒页面,看起来不du支持该--files0-from选项。

您可以将上面的命令更改为这样,以使其在 busybox 上运行:

find -type f -mtime +60 -print0 | xargs -0 du -ch | tail -n1

上面的方法也适用于名称中包含空格和换行符的文件,但如果命令找到太多文件,则可能无法正常工作find。请参阅下面的内容评论。如果您觉得文件可能太多,您可以尝试此页面上的其他答案。

答案2

原则上这很简单:只需告诉立即find运行du一堆文件即可。 不幸的是,这不能可靠地工作,因为可以多次执行该命令,它只尝试对参数进行分组,并且如果它们的总长度超过系统的命令行长度限制,则不可能对所有参数进行分组。事实上 BusyBox find (至少是我刚才测试的版本)根本不尝试分组:一次处理一个参数, line 。没有办法确保得到一行。
find . -type f -mtime +60 -exec du -smc {} +
-exec … {} +-exec … {} +-exec … {} \;total

可以用 告诉GNUdu读取任意长的文件名列表--files0-from,但是其他版本的du,特别是 BusyBox 中的版本,只能从命令行获取文件名。

因此,如果您不能假设您拥有 GNU du,则无法避免du多次运行,这意味着您需要另一个工具来进行求和,而这又要求du不对大小进行舍入。如果 awk 的输出是可解析的,则求和很简单du

如果您可以假设文件名中没有换行符,或者您可以排除包含换行符的路径,则 的输出du很容易解析:每行只有一个文件。

newline='
'
find . ! -path "*${newline}*" -type f -mtime +60 -exec du -k {} + |
awk '{kB += $1} END {printf "%d MB\n", (kB + 512) / 1024}'

答案3

如果你想要累计磁盘使用情况(正如您的使用所du建议的那样)超过 60 天的常规文件,只需要移植到 GNU 和 busybox 系统(尽管请注意,busybox 中包含哪些命令以及它们支持的功能可以在构建时配置,所以你永远不知道适用于一个 busybox 实例的方法是否适用于下一个实例),你可以这样做:

find . -type f -mtime +59 -print0 |
  xargs -r0 stat -c '%D:%i %b' | awk '
    !seen[$1]++ {sum += $2}
    END {print sum * 512}'

(是的,您需要-mtime +59超过 60 x 24 小时-mtime +60的文件。与 60.9 天的文件不匹配,因为该文件向下舍入为 60 天,并且 60 不大于 60)

这报告了总字节数。硬链接(或其他情况,例如绑定安装(同一个文件可能有多个路径)只计算一次(就像 GNUdu那样;如果硬链接作为单独的参数传递而不是在单个目录参数的遍历中找到,则 busyboxdu不会这样做)。但是,与 一样du,它不会检测在非硬链接文件之间共享某些数据的情况,例如在 btrfs 等文件系统上复制文件时cp --reflink=always或文件系统执行重复数据删除时。

这应该相当于 GNU 特定的:

find . -type f -mtime +59 -print0 |
  du -cB1 --files0-from=- |
  awk 'END{print $1}'

POSIXly,假设所有文件都位于同一文件系统上,您可以执行以下操作:

LC_ALL=C LS_BLOCK_SIZE=512 BLOCKSIZE=512 POSIXLY_CORRECT=1 \
  find . -type f -mtime +59 -exec ls -nisqd {} + | awk '
    !seen[$1]++ {sum += $2}
    END {print sum * 512}'

(要LS_BLOCK_SIZE=512 BLOCKSIZE=512 POSIXLY_CORRECT=1解决这样一个事实,即默认情况下ls,GNU 等某些实现ls不兼容 POSIX。它不能与ls不支持 的busybox 一起使用-q。但是,因为它总是在文件路径中呈现换行符?(这也不兼容 POSIX) ),-q那里不需要)。

之后(这里是 GNU 系统):

$ seq 10000 > a
$ truncate -s14T a
$ ln a b
$ touch -d '-60 days' a
$ BLOCKSIZE=1 ls -lis --full-time
total 98304
59944369 49152 -rw-rw-r-- 2 me me 15393162788864 2019-07-29 09:49:25.933 +0100 a
59944369 49152 -rw-rw-r-- 2 me me 15393162788864 2019-07-29 09:49:25.933 +0100 b
$ date --iso-8601=s
2019-09-27T09:50:03+01:00
$ du -h
52K     .

全部给我49152,这是两者的累积磁盘使用量ab但不同于它们大小的总和 (28 TiB) 或它们的磁盘使用量大小 (49152 x 2)。

(请注意,上面的 52K 还包括当前目录文件的磁盘使用量(.在我的例子中为 4KiB))。

为表观尺寸的总和。

find . -type f -mtime +59 -print0 |
  xargs -r0 stat -c %s | awk -v sum=0 '
    {sum += $0}; END{print sum}'

或者使用 GNU du

find . -type f -mtime +59 -print0 |
  du -cbl --files0-from=- |
  awk 'END{print $1}'

或者 POSIXly(这里没有关于单个文件系统的限制):

LC_ALL=C find . -type f -mtime +59 -exec ls -nqd {} + |
  awk -v sum=0 '{sum += $5}; END {print sum}'

在上面的示例中,它们都给出:30786325577728(28 TiB)。

相关内容