【问题标题】:Calculate combined filesize of thousands of files计算数千个文件的组合文件大小
【发布时间】:2021-12-15 17:43:46
【问题描述】:

我们有一个软件包,它通过为一批文件分配一个作业编号来执行任务。批处理中可以包含任意数量的文件。然后将文件存储在类似于以下的目录结构中:

/asc/array1/.storage/10/10297/10297-Low-res.m4a
...
/asc/array1/.storage/3/3814/3814-preview.jpg

文件名是自动生成的。 .storage中的目录是文件号的千分位。

还有一个将工作编号和文件编号与相关客户相关联的数据库。运行 SQL 查询,我可以列出作业编号、客户端和文件的完整路径。示例:

213     sample-data     /asc/array1/.storage/10/10297/10297-Low-res.m4a
...
214     client-abc      /asc/array1/.storage/3/3814/3814-preview.jpg

我的任务是计算每个客户端使用的总存储空间。因此,我编写了一个快速而肮脏的 bash 脚本来遍历每一行和 du 文件,并将其添加到关联数组中。然后,我计划将其回显出来或生成一个 CSV 文件,以便摄取到 PowerBI 或其他一些工具中。这是处理这个问题的最好方法吗?这是脚本的副本:

#!/bin/sh

declare -A clientArr

# 1 == Job Num
# 2 == Client
# 3 == Path
while read line; do
    client=$(echo "$line" | awk '{ print $2 }')
    path=$(echo "$line" | awk '{ print $3 }')

    if [ -f "$path" ]; then
        size=$(du -s "$path" | awk '{ print $1 }')
        clientArr[$client]=$((${clientArr[$client]}+${size}))
    fi
done < /tmp/pm_report.txt

for key in "${!clientArr[@]}"; do
    echo "$key,${clientArr[$key]}"
done

【问题讨论】:

  • 对文件的每一行调用awk 三次、echo 两次和du 一次总是要花很长时间。尝试运行您需要运行一次的任何内容,并在一次调用 awkpython 或数据库中累积结果。
  • 您的问题中是否存在实际问题?
  • 最好的方法是在您的数据库中添加一个包含文件大小的列。
  • @MarkRansom 遗憾的是,数据库是由软件控制的。不过,我可以与他们讨论将其添加为一项功能。

标签: linux bash du


【解决方案1】:

假设:

  • 你有 GNU coreutils du
  • 文件名不包含空格

这没有 shell 循环,调用 du 一次,并迭代 pm_report 文件两次。

file=/tmp/pm_report.txt

awk '{printf "%s\0", $3}' "$file" \
| du -s --files0-from=- 2>/dev/null \
| awk '
    NR == FNR {du[$2] = $1; next}
    {client_du[$2] += du[$3]}
    END {
      OFS = "\t"
      for (client in client_du) print client, client_du[client]
    }
  ' - "$file"

【讨论】:

  • 我在指向 % 符号的“printf %s0”处遇到 awk 语法错误。
  • 如果有帮助,我将在软件开发人员提供的 Docker 容器中运行 GNU Awk 4.0.2。
  • 糟糕,我使用了错误的引号。使用带有双引号的printf "%s\0",。我将编辑我的答案。
【解决方案2】:

使用文件foo:

$ cat foo
213     sample-data     foo          # this file
214     client-abc      bar          # some file I had in the dir
215     some            nonexistent  # didn't have this one

还有 awk:

$ gawk '                             # using GNU awk
@load "filefuncs"                    # for this default extension
!stat($3,statdata) {                 # "returns zero upon success"
    a[$2]+=statdata["size"]          # get the size and update array
}
END {                                # in the end
    for(i in a)                      # iterate all
        print i,a[i]                 # and output
}' foo foo                           # running twice for testing array grouping

输出:

client-abc 70
sample-data 18

【讨论】:

  • 我在 @load "filefuncs" 处遇到语法错误,指向加载中的 l。这是软件开发人员在 Docker 容器中提供的 GNU Awk 4.0.2。
  • Feature history 提到 --load 出现在 4.1 版中,但在早期版本中提到了扩展。我不知道它们是否存在或如何在您的版本中使用它们。也许是时候升级了……
猜你喜欢
  • 2012-02-06
  • 1970-01-01
  • 2011-08-17
  • 1970-01-01
  • 1970-01-01
  • 2019-01-06
  • 1970-01-01
  • 2010-10-10
  • 2010-12-22
相关资源
最近更新 更多