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

I'm getting an unexpected result from an attempt to use a module, Filesys::DfPortable, on CPAN. I'm seeing the same results in blocks, with different filesystems used as arguments to dfportable. The output of my code looks like this:

$ perl ~/Documents/perl-libdirs-installTime.pl
/usr/lib/perl5/5.40/x86_64-cygwin-threads  installarchlib
Total 1k blocks used in installarchlib:  175,087,368
/usr/share/perl5/5.40                      installprivlib
Total 1k blocks used in installprivlib:  175,087,368

So here's the code I'd like help with:

#!/usr/bin/env perl # use strict; use warnings; use Config; use Number::Format qw(:subs); use Filesys::DfPortable; my $mlen = 0; my %hop; my @lodirs = qw(installarchlib installprivlib); for (@lodirs) { my $p = $Config{ $_ }; $mlen = length( $p ) > $mlen ? length( $p ) : $mlen; $hop{ $_ } = $p; } $mlen += 2; for (sort keys( %hop )) { printf( "%-${mlen}s%s\n", $hop{ $_ }, $_ ); my $mea = dfportable( $hop{ $_ }, 1024 ); printf "Total 1k blocks used in %s: %s\n", $_ , format_number( $mea->{bused} ); }

I started working on this little script in Linux and I see the same anomalous results on CygPerl. I don't think it's a PEBKAC but I need other eyes to check it out. Thanks very much, Monks / Nuns.

    – Soren
Apr 10, 2026 at 15:34 UTC

A just machine to make big decisions
Programmed by fellows (and gals) with compassion and vision
We'll be clean when their work is done
We'll be eternally free yes, and eternally young
Donald Fagen —> I.G.Y.
(Slightly modified for inclusiveness)

Replies are listed 'Best First'.
Re: An anomaly with Filesys::DfPortable, I need your eyes
by dave_the_m (Monsignor) on Mar 09, 2026 at 22:51 UTC
    Are you sure they're actually two different filesystems? What do the following two commands show?
    df -k /usr/lib/perl5/5.40/x86_64-cygwin-threads /usr/share/perl5/5.4 +0 ls -ld /usr/lib/perl5/5.40/x86_64-cygwin-threads /usr/share/perl5/5.4 +0

    Dave.

      Another check is to use abs_path from Cwd to check whether they're resolving to the same file perhaps. I use the following shell function:

      abs_path () { perl -MCwd=abs_path -lE 'say abs_path( $_ ) for @ARGV' "$@" }

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

        I ran your code (in Cygwin's shell), Fletch, thanks. My directories are absolute paths:

        $ abs_path `perl -MConfig -le 'printf "%s %s", $Config{installprivlib}, $Config{installarchlib}'`
        /usr/share/perl5/5.40
        /usr/lib/perl5/5.40/x86_64-cygwin-threads
        

        I tried an idea that occurred to me (and is indirectly suggested by Dave above). The 'nix command du:

         
        $ du -sh `perl -MConfig -le 'printf "%s %s", $Config{installprivlib}, $Config{installarchlib}'`
        27M     /usr/share/perl5/5.40
        24M     /usr/lib/perl5/5.40/x86_64-cygwin-threads
        

        I'd say that du is doing something different (and what I want) from what Filesys::DfPortable dfportable is doing. The above question from Dave is on target. The two dirs are on the same filesystem. I was naively believing that I'd get the sum of the usage of each directory tree, not of the entire filesystem containing the directory tree(s). A significant distinction, eh. Despite the use of the term Filesys. Ok, that warrants a duh.

            – Soren
        Mar 10, 2026 at 16:21 UTC

      On Unix (but not on Windows), lstat and stat on the directories can help.

      (Actually, this works for every file, but df only looks at mountpoints, i.e. directories.)

      #!/usr/bin/perl use strict; use warnings; for my $d (qw( / /bin /sbin /lib /usr /usr/bin /usr/sbin /usr/lib /pro +c /sys /run /tmp /var/run /var/tmp )) { print "$d: on device ",(lstat($d))[0]; if (-l $d) { print " (symlink to ",readlink($d),")"; } print "\n"; }

      Running that on a recent debian in a VM shows:

      $ perl lstat.pl /: on device 1795 /bin: on device 1795 (symlink to usr/bin) /sbin: on device 1795 (symlink to usr/sbin) /lib: on device 1795 (symlink to usr/lib) /usr: on device 1795 /usr/bin: on device 1795 /usr/sbin: on device 1795 /usr/lib: on device 1795 /proc: on device 99 /sys: on device 100 /run: on device 105 /tmp: on device 1795 /var/run: on device 1795 (symlink to /run) /var/tmp: on device 1795 $

      Most stuff is on device 1795, the root filesystem of this VM. /proc is a completely different device (that of the virtual proc filesystem), and so are /run (105) and /sys (100). /var/run is a symlink stored on device 1795 (root filesystem), it points to /run, which is on device 105.

      Due to the way symlinks work, everything that appears to be in /var/run/ is really in /run.

      Changing lstat() to stat() allows the system to follow symlinks instead of working on them:

      #!/usr/bin/perl use strict; use warnings; for my $d (qw( / /bin /sbin /lib /usr /usr/bin /usr/sbin /usr/lib /pro +c /sys /run /tmp /var/run /var/tmp )) { print "$d: on device ",(stat($d))[0]; if (-l $d) { print " (followed symlink to ",readlink($d),")"; } print "\n"; }
      $ perl stat.pl /: on device 1795 /bin: on device 1795 (followed symlink to usr/bin) /sbin: on device 1795 (followed symlink to usr/sbin) /lib: on device 1795 (followed symlink to usr/lib) /usr: on device 1795 /usr/bin: on device 1795 /usr/sbin: on device 1795 /usr/lib: on device 1795 /proc: on device 99 /sys: on device 100 /run: on device 105 /tmp: on device 1795 /var/run: on device 105 (followed symlink to /run) /var/tmp: on device 1795 $

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

        Alexander, I want to acknowledge your very substantial reply, I've been busy with other things the last few days and didn't have time to do that. And still don't right now. So, I am going to edit this node when I have time to do your suggestions justice, rather than rush through it. Thanks for your thoughts.

        EDIT


        Ok, I've had a chance to look at Alexander's post, and download and run the code.

        Here's how the data looks from running your first script, on one of my Gnu/Linux systems.

        $ perl stat-and-friends.pl
        /: on device 2082
        /bin: on device 2082 (symlink to usr/bin)
        /sbin: on device 2082 (symlink to usr/sbin)
        /lib: on device 2082 (symlink to usr/lib)
        /usr: on device 2082
        /usr/bin: on device 2082
        /usr/sbin: on device 2082
        /usr/lib: on device 2082
        /proc: on device 23
        /sys: on device 22
        /run: on device 25
        /tmp: on device 2082
        /var/run: on device 2082 (symlink to /run)
        /var/tmp: on device 2082
        

        So. Interesting. This seems useful for getting a picture of how resources are being allocated to the various filesystems. I don't think I've ever actually used perl's stat or lstat in a program I've written. I'm going to have to remember that perl has these built-in functions and they could be useful.

        Thanks for waiting a long time for my reply, Alexander :-)


            – Soren
        Apr 01, 2026 at 16:31 UTC

Re: An anomaly with Filesys::DfPortable, I need your eyes
by Intrepid (Curate) on Mar 13, 2026 at 19:29 UTC

    I've finished the script: I have decided to share it here, although it's just a small script, but some readers might want to save it to their ~/.local/bin/ or wherever they keep their little tools. If the reader decides to save and run the script, most likely s/he'll need to install just one CPAN module, Filesys::DiskUsage.

    #!/usr/bin/env perl # Last modified: 2026-03-11T20:39:00-04:00 use strict; use warnings; use Config qw( config_re ); use Filesys::DiskUsage qw( du ); # use Data::Dumper; my @r = config_re(q/\S+(lib|arch)exp/); my %eos; my @inst = map { ( split "=", $_, 2 )[0] } @r; my @dirslist = @Config::Config{@inst}; my $sl = 0; for ( @dirslist ) { $sl = length $_ > $sl ? length $_ : $sl; } $sl += 2; # horizontal spacing for my $tag (@inst) { my $f = $Config::Config{$tag}; $eos{ $tag } = [$f, du({ 'human-readable' => 1, 'sector-size' => 1024 } , $f )]; } # "vendorarchexp" is longest tag, 13 chars. do { no warnings 'uninitialized'; $eos{$_}[1] = ($eos{$_}[1] eq undef ? 0 : $eos{$_}[1]); printf qq^%-${sl}s %-13s %s\n^ => $eos{$_}[0] , $_ , $eos{$_}[1] } for sort keys %eos; #eof

    For example, on a CygPerl installation the (system) perl generates the following nicely-formatted list:

    $ perl ~/Scripts-finished/perlinstDirs.pl
    
    /usr/lib/perl5/5.40/x86_64-cygwin-threads archlibexp 23.37M /usr/share/perl5/5.40 privlibexp 24.13M /usr/local/lib/perl5/site_perl/5.40/x86_64-cygwin-threads sitearchexp 61.46M /usr/local/share/perl5/site_perl/5.40 sitelibexp 186.12M /usr/lib/perl5/vendor_perl/5.40/x86_64-cygwin-threads vendorarchexp 17.58M /usr/share/perl5/vendor_perl/5.40 vendorlibexp 57.11M

    Regards all,
        – Soren

    Apr 10, 2026 at 15:34 UTC