patternMinor
Clean way to get size of directory
Viewed 0 times
directorysizewaygetclean
Problem
I'm working on a Unix machine where I can't use more than vanilla Perl, and I'm using Perl5.8. This script exits with a 1 if the current directory size is smaller than 1 GB (the character after
This is gross, but I know the data is in
-d is a literal "tab" character).my $du = `du --si | tail -1 | cut -d" " -f1`;
chomp $du;
if (substr($du, -1) ne "G") {
exit 1;
}
exit 0;This is gross, but I know the data is in
du --si so I can write it in 30 seconds. Is there a cleaner, more robust way?Solution
I agree with @rolfl that this would be much simpler as a one-line shell pipeline. The
However, the
The second version also works even if the total is in the terabyte or exabyte range.
There is an inefficiency, though: you should be able to exit early as soon as you find that the total exceeds 1 GB. For that, you would go back to Perl, but with a proper Perl program instead of a wrapper around
-s option to du makes it produce a total. awk is a good tool to use for processing multi-column text.du -s --si | awk '$1 ~ /G/ { exit 1 }'However, the
--si option seems to be a non-portable GNU extension. A more portable version would look at the number of 512-byte blocks. The magic number 1953125 is \$\dfrac{10^9}{512}\$.du -s | awk '$1 < 1953125 { exit 1 }'The second version also works even if the total is in the terabyte or exabyte range.
There is an inefficiency, though: you should be able to exit early as soon as you find that the total exceeds 1 GB. For that, you would go back to Perl, but with a proper Perl program instead of a wrapper around
du.use File::Find;
use strict;
my $sum = 0;
my %seen_inodes;
find(sub {
my ($inode, $blocks) = (stat)[1, 12] or die "${File::Find::name}: $!";
# Do not double-count hard links
if (!$seen_inodes{$inode}) {
$seen_inodes{$inode} = 1;
$sum += 512 * $blocks;
exit 0 if $sum >= 1_000_000_000;
}
}, ".");
exit 1;Code Snippets
du -s --si | awk '$1 ~ /G/ { exit 1 }'du -s | awk '$1 < 1953125 { exit 1 }'use File::Find;
use strict;
my $sum = 0;
my %seen_inodes;
find(sub {
my ($inode, $blocks) = (stat)[1, 12] or die "${File::Find::name}: $!";
# Do not double-count hard links
if (!$seen_inodes{$inode}) {
$seen_inodes{$inode} = 1;
$sum += 512 * $blocks;
exit 0 if $sum >= 1_000_000_000;
}
}, ".");
exit 1;Context
StackExchange Code Review Q#48626, answer score: 4
Revisions (0)
No revisions yet.