【问题标题】:Get total size of a list of files in UNIX获取 UNIX 中文件列表的总大小
【发布时间】:2014-03-26 05:44:54
【问题描述】:

我想运行一个find 命令来查找某个文件列表,然后遍历该文件列表以运行一些操作。我还想找到该列表中所有文件的总大小。

我想先列出文件,然后再进行其他操作。有没有一种简单的方法可以只报告列表中所有文件的总大小?

本质上,我试图在下面的代码 sn-p 中为“total_size”变量找到一个单行:

#!/bin/bash
loc_to_look='/foo/bar/location'

file_list=$(find $loc_to_look -type f -name "*.dat" -size +100M)

total_size=???

echo 'total size of all files is: '$total_size

for file in $file_list; do
         # do a bunch of operations
done

【问题讨论】:

  • 您可以在find 命令中使用printf "%p %s\n" 来显示名称+大小。
  • @fedorqui 如果她的find 版本支持-printf。某种形式的-exec stat -f '%z' {} \;(取决于您的系统对stat 的实现)也可以工作。
  • @fedorqui:您还必须在 for 循环之前拆分文件名和大小...
  • 无论如何都不建议将文件名列表存储在平面字符串中,因为您无法轻松处理包含空格的文件名。

标签: bash shell unix


【解决方案1】:

您应该能够将$file_list 传递给du

du -ch $file_list | tail -1 | cut -f 1

du 选项:

  • -c显示总数
  • -h 人类可读(即 17M)

du 将为每个文件打印一个条目,然后是总数(-c),因此我们使用tail -1 仅修剪到最后一行,cut -f 1 将该行修剪到第一行列。

【讨论】:

  • 感谢@sanmiguel!我将命令放在变量的反引号中:D
  • 这是一个不错的答案,但请记住,du 打印的实际磁盘使用情况四舍五入到(通常)4 KB 的倍数,而不是逻辑文件大小。 for i in {0..9}; do echo -n $i > $i.txt; done; du -ch *.txt => 40K total 而不是 10 total
  • 你是对的,虽然在这种情况下 ±4KB 的差异可以忽略不计,因为我们只处理超过 100MB 的文件... ;-)
  • 另外,请检查您的 du 版本。如果您使用的是 GNU 工具,则可以将 --apparent-size 添加到 du 选项以获得与 ls 显示的相同大小的列表。
  • 如果 $files_list 中的文件名包含空格怎么办?我试过用\ 转义空间,但没有成功。
【解决方案2】:

此代码将所有文件的可信 ls 中的所有字节加起来(它不包括所有目录......显然它们是每个文件夹/目录 8kb)

cd /; find -type f -exec ls -s \; | awk '{sum+=$1;} END {print sum/1000;}'

注意:以root身份执行。结果以兆字节为单位。

【讨论】:

    【解决方案3】:

    这里解释的方法有隐藏的错误。当文件列表很长时,它会超出 shell 命令大小的限制。最好使用 du 来使用这个:

    find <some_directories> <filters> -print0 | du <options> --files0-from=- --total -s|tail -1
    

    find 生成以空结尾的文件列表,du 从标准输入中获取并计数。 这与 shell 命令大小限制无关。 当然,你可以在 du 中添加一些开关来获取逻辑文件大小,因为默认情况下 du 告诉你文件将占用多少物理空间。

    但我认为这不是程序员的问题,而是 unix 管理员的问题 :) 那么对于 stackoverflow 来说,这不是主题。

    【讨论】:

    • 这是迄今为止最好的答案。不需要 awk 或 shell 变量。
    • 我们可以删除 -print0--files0-from=- 并将它们替换为对 xargs 的调用,例如find . | xargs du.
    • 用xargs多次调用du命令,会慢很多,资源利用率更高。否则,当任何文件名包含任何换行符时,它不会阻止正确运行。然后 find with xargs 应该有 'null end' 选项,对于 xargs 它将是 --null 或 -0(数字零)开关。
    • 有人将此标记为正确答案!比其他任何人都好。
    • 如果没有-print0,有没有办法做到这一点?我的文件系统中到处都是files.txt,我用换行符而不是空终止来生成。通常我使用xargs -d'\n'但我不能让 du 总结令人沮丧的尺寸。
    【解决方案4】:

    ls -l | tr -s ' ' | cut -d ' ' -f &lt;field number&gt; 是我经常使用的东西。

    第 5 个字段是大小。将该命令放入 for 循环并将大小添加到累加器中,您将获得目录中所有文件的总大小。比学习 AWK 更容易。另外,在命令替换部分,您可以使用 grep 来限制您要查找的内容(^- 用于文件等)。

    total=0
    
    for size in $(ls -l | tr -s ' ' | cut -d ' ' -f 5) ; do
      total=$(( ${total} + ${size} ))
    done
    
    echo ${total}
    

    【讨论】:

    • 答案可能是正确的,但为了让其他人理解,请添加一些文字以更好地描述。
    【解决方案5】:

    @Znik 提供的方法有助于解决文件列表过长时遇到的错误。

    然而,在 Solaris(它是一个 Unix)上,du 没有 -c--total 选项,因此似乎需要一个计数器来累积文件大小。

    此外,如果您的文件名包含特殊字符,这将无法顺利通过管道 (Properly escaping output from pipe in xargs )。

    基于最初的问题,以下适用于 Solaris(对变量的创建方式稍作修改):

    file_list=($(find $loc_to_look -type f -name "*.dat" -size +100M))
    printf '%s\0' "${file_list[@]}" | xargs -0 du -k | awk '{total=total+$1} END {print total}'
    

    输出以 KiB 为单位。

    【讨论】:

    • 不,没有错误:) 通过管道传输的文件列表,它是使用一些管道缓冲区逐行传输的。你是对的,Solaris 没有一些选择。但是没有障碍,可以为 solaris 安装 GNU shell 实用程序。不幸的是,Solaris 目前是一步步的异国系统,它在 Oracle 手中,而且非常昂贵。许多系统已经被带有 linux 的 intel 平台所取代,因为 TCO 低得多,并且与用于 solaris 的软件高度兼容。
    【解决方案6】:

    du 的问题在于它也会增加目录节点的大小。当您只想总结文件大小时,这是一个问题。 (顺便说一句,我觉得 du 没有忽略目录的选项很奇怪。)

    为了增加当前目录下文件的大小(递归),我使用如下命令:

    ls -laUR | grep -e "^\-" | tr -s " " | cut -d " " -f5 | awk '{sum+=$1} END {print sum}'
    

    它是如何工作的:它递归地列出所有文件 ("R"),包括显示文件大小 ("l") 的隐藏文件 ("a") 并且不对其进行排序 ("U")。 (当目录中有很多文件时,可能会出现这种情况。)然后,我们只保留以“-”开头的行(这些是常规文件,因此我们忽略目录和其他内容)。然后我们将随后的空格合并为一个,以便ls 的表格对齐输出的行成为每行中以单空格分隔的字段列表。然后我们cut每一行的第5个字段,里面存放的是文件大小。 awk 脚本将这些值汇总到 sum 变量中并打印结果。

    【讨论】:

    • 在某些 shell 中,您可以使用千位分隔符显示结果:printf "%'.0f\n" $(ls -laUR | grep -e "^\-" | tr -s " " | cut -d " " -f5 | awk '{sum+=$1} END {print sum}')
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    • 2012-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多