Home > Software engineering >  Calculate combined filesize of thousands of files
Calculate combined filesize of thousands of files

Time:12-16

We have a software package that performs tasks by assigning the batch of files a job number. Batches can have any number of files in them. The files are then stored in a directory structure similar to this:

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

The filename is generated automatically. The directory in .storage is the thousandths digits of the file number.

There is also a database which associates the job number and the file number with the client in question. Running a SQL query, I can list out the job number, client and the full path to the files. Example:

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

My task is to calculate the total storage being used per client. So, I wrote a quick and dirty bash script to iterate over every single row and du the file, adding it to an associative array. I then plan to echo this out or produce a CSV file for ingest into PowerBI or some other tool. Is this the best way to handle this? Here is a copy of the script as it stands:

#!/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

CodePudding user response:

Assuming:

  • you have GNU coreutils du
  • the filenames do not contain whitespace

This has no shell loops, calls du once, and iterates over the pm_report file twice.

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"

CodePudding user response:

Using file 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

and the 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

Output:

client-abc 70
sample-data 18
  • Related