http://www.perlmonks.org?node_id=11138963

ovedpo15 has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!
I have a tool (written in Perl in Linux env) which keeps configurations in user's home directory (or a path that he provides). I noticed that users open a lot of tickets lately, complaining about different issues that caused by overfilled home directory (after some debugging).
I want to add some code which checks the size of used space, and if it's more than 90%, I want to print a warning to the stdout, saying that you might get different errors. I'm familiar with df and du, but I was wondering what would be the right way to do it (Maybe a basic Perl way, without installing additional modules)? As I understand, the pseudo code should look something like:
my $used_space = get_used_space($path); if ($used_space >= 90) { print("Warning: please clean the directory: $path\n"); }
I'm also opened to other suggestion on how to warn the user.
Also, please note that we provide an option to choose a specific path (and not use the default home directory), so the check should be performed on $path and not just ~/.

Replies are listed 'Best First'.
Re: How to know how much used space of a path?
by choroba (Cardinal) on Nov 19, 2021 at 23:03 UTC
    Searching CPAN reveals Filesys::Df and Filesys::DfPortable by the same author. I have no experience with either but they should do what you want.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: How to know how much used space of a path?
by NERDVANA (Deacon) on Nov 21, 2021 at 13:41 UTC
    The "right way" is whatever solves your problem; for a system-specific problem that usually means tying into some part of the system that knows the answer rather then inventing it yourself in pure perl.

    For unix, in addition to needing to find out which volume holds the home directory and how much free space it has, you need to find out whether this user has a quota limit (i.e. on a multi-user system). If this is an in-house application where only a few environments are relevant, I'd just shell out to df -k /path. If you need something portable, take a long look around cpan. (surely someone has published something for this in the last 20 years?) If not, congratulations! you found an opportunity to contribute :-)

Re: How to know how much used space of a path?
by hanspr (Sexton) on Nov 20, 2021 at 05:20 UTC
    You could use a recursive sub to get the size of each file in the path and accumulate de bytes and then return the total bytes accumulated.

    That gives you the size of the directory, and then you need a reference to the maximum allowed size to be able to get a percentage.


    #!/usr/bin/perl our $used = get_used_space("/path/to/dir",10000000); print "Used space -> $used %\n"; sub get_used_space { my $dir = shift; my $max = shift; if ($max <= 0) { return 0; } my $current_size = get_space($dir); return int(($current_size / $max) * 10000)/100; } sub get_space { my $dir = shift; my $d; my $bytes = 0; opendir($d,$dir); while (my $f = readdir($d)) { if ($f eq '.' || $f eq '..') { next; } my $file = "$dir/$f"; if (-d $file) { $bytes += get_space("$file"); } if (-f $file) { my $size = -s "$file"; $bytes += $size; } } return $bytes; }

      Nitpicks:

      • You're reimplementing the standard File::Find module which does this (correctly) for you (to say nothing of other similar modules available from CPAN such as File::Find::Rule, Path::Tiny, Path::Iterator::Rule, . . .)
      • On OSen and/or filesystems which allow sparse files there's usually a way to ask du to account for that fact and get the actual space used by the file; summing the sizes returned by stat(2) (via caling stat or the -s operator) won't.
      • You don't check the return value from opendir; ALWAYS CHECK THE RETURN VALUE FROM SYSTEM CALLS.
      • You're needlessly stringifying in a couple places, e.g. -s "$file"; not necessarily a problem in this particular case but it's a bad habit to develop. Somewhere down the road you're going to have an object instance for a class which has overloaded stringification that you DIDN'T mean to turn into just a string and then you're going to have to debug why you're getting an error about not being able to locate method foo via package bar from somewhere deep down in your code.

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.