1

I'm following @zdim's recursive solution in this question fastest way to sum the file sizes by owner in a directory to get my file sizes summed up by year-month

perl -MFile::Find -E' use POSIX;
    $dir = shift // "."; 
    find( sub { 
        return if /^\.\.?$/; 
        my ($mtime, $size) = (stat)[9,7];
        my $yearmon = strftime "%Y%m",localtime($mtime);
        $rept{$yearmon} += $size ;
    }, $dir ); 
    say ("$_ => $rept{$_} bytes") for sort keys %rept
'

It gives results like this.

201701 => 7759 bytes
201702 => 530246 bytes
201703 => 3573094 bytes
201704 => 425827 bytes
201705 => 3637771 bytes
201706 => 2325391018 bytes
201707 => 127005 bytes
201708 => 2303 bytes
201709 => 231465431 bytes
201710 => 273667 bytes
201711 => 6397659 bytes
201712 => 333587 bytes
201802 => 874676 bytes
201803 => 147825681 bytes
201804 => 84971454 bytes
201805 => 3483547 bytes
201806 => 8004797 bytes
201807 => 184676 bytes
201808 => 1967947 bytes
201809 => 1592310 bytes
201810 => 24176 bytes
201811 => 883378 bytes
201812 => 6661592 bytes
201901 => 33979401 bytes

But I need to include year-wise totals after printing all available months in a given year, like below

201710 => 1111 bytes
201711 => 2222 bytes
201712 => 3333 bytes
2017  => 6666 bytes ( summed up )
201803 => 11111 bytes
201809 => 22222 bytes
2018  => 33333 bytes ( summed up )

How do I get that?. There might be blanks in a year-month and it need not end with month 12 for every year.

zdim
  • 64,580
  • 5
  • 52
  • 81
stack0114106
  • 8,534
  • 3
  • 13
  • 38
  • What's the issue? Given the code you already have, this looks like something you should be able to do. One way would be to use an hash of hashes where years are the first keys and months the second ones (so you'll write something like `$rept{$year}->{$month} += $size`). It's a little bit more verbose, but definitely reasonable. – Dada Mar 22 '19 at 13:53
  • @Dada.. yes, you are right.. but now I realize that I would have missed ikegami's hack to it.. – stack0114106 Mar 22 '19 at 17:43

2 Answers2

3

Two small changes will do the trick.

perl -MFile::Find -E' use POSIX;
    $dir = shift // "."; 
    find( sub { 
        return if /^\.\.?\z/;                             # Fixed $ -> \z
        my ($mtime, $size) = (stat)[9,7];
        my $yearmon = strftime "%Y%m",localtime($mtime);
        $rept{$yearmon} += $size;
        $rept{substr($yearmon, 0, 4)} += $size;           # <---
    }, $dir ); 
    say "$_ => $rept{$_} bytes"
        for sort { "${a}99" cmp "${b}99" } keys %rept;    # <---
'
ikegami
  • 367,544
  • 15
  • 269
  • 518
2

Given that you've built the %rept hash in the first part of your code, the display section should be something like this:

# Keep track of current year and current year total
my ($year, $year_total);

for (sort keys %rept) {
  # Get the year from the current record
  my $this_year = substr($_, 0, 4);
  # If the year has changed, then print a total line
  # and reset the year total.
  if (defined $year and $year ne $this_year) {
    say "$year   => $year_total bytes";
    $year_total = 0;
  }
  # Add to the year total and store the current year
  $year_total += $rept{$_};
  $year = $this_year;

  say "$_ => $rept{$_} bytes";
}

# Final year total line
say "$year   => $year_total bytes";
Dave Cross
  • 68,119
  • 3
  • 51
  • 97