0

I have a script that parses df into something that perl can use.

 1 #!/usr/bin/perl
 2 use strict;
 3 use warnings;
 4
 5 my @headers = qw(name size used free capacity mount);
 6 my @df = `df -k`;
 7 shift @df;  # get rid of the header
 8
 9 my %devices;
10 for my $line (@df) {
11     my %info;
12     @info{@headers} = split /\s+/, $line;  # note the hash slice
13     $info{capacity} = _percentage_to_decimal($info{capacity});
14     $devices{ $info{mount} } = \%info;
15 }
16
17 # Change 12.3% to .123
18 sub _percentage_to_decimal {
19     my $percentage = shift;
20     $percentage =~ s{%}{};
21     return $percentage / 100;
22 }
23 # Now the information for each device is in a hash of hashes.
24
25 # Show how much space is free in device /dev/ad4s1e
26 print $devices{"/production/log"}{free} ;
27 print "\n";
28 for my $info (values %devices) {
29     # Skip to the next device if its capacity is not over 60%.
30     next unless $info->{capacity} > .10;
31
32     # Print some info about each device
33     printf "%s is at %d%% with %dK remaining.\n",
34         $info->{mount}, $info->{capacity}*100, $info->{free};
35 }

However I keep getting these warnings.

Use of uninitialized value in substitution (s///) at ./get_df line 21.
Use of uninitialized value in division (/) at ./get_df line 22.
Use of uninitialized value in hash element at ./get_df line 15.
Use of uninitialized value in substitution (s///) at ./get_df line 21.
Use of uninitialized value in division (/) at ./get_df line 22.
Use of uninitialized value in hash element at ./get_df line 15.
Use of uninitialized value in substitution (s///) at ./get_df line 21.
Use of uninitialized value in division (/) at ./get_df line 22.
Use of uninitialized value in hash element at ./get_df line 15.
Use of uninitialized value in substitution (s///) at ./get_df line 21.
Use of uninitialized value in division (/) at ./get_df line 22.
Use of uninitialized value in hash element at ./get_df line 15.
Use of uninitialized value in substitution (s///) at ./get_df line 21.
Use of uninitialized value in division (/) at ./get_df line 22.
Use of uninitialized value in hash element at ./get_df line 15.
9006792
/production/log is at 70% with 9006792K remaining.
/ is at 37% with 17037532K remaining.
/production is at 11% with 13171728K remaining.
/export/home is at 24% with 11199904K remaining.
/production/archive is at 18% with 8095796K remaining.
/boot is at 28% with 68351K remaining.

UPDATE: I looked at the DF module on CPAN last night at home, but I would have to get sysadmin approval to get it installed. On the df the Filesystem is too long, so it gets printed to another line. This messed up the data dumper print out - some of the hash values get labeled undef.

casper@casperbox]:~/.wjohnson> df -k
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
                      28313732   9816924  17035356  37% /
/dev/sda1               101086     27516     68351  29% /boot
tmpfs                  2987896         0   2987896   0% /dev/shm
/dev/mapper/VolGroupPROD-ExportHome
                      15481840   3495504  11199904  24% /export/home
/dev/mapper/VolGroupPROD-Production
                      15481840   1523692  13171716  11% /production
/dev/mapper/VolGroupPROD-ProdLog
                      30963708  20410952   8979892  70% /production/log
/dev/mapper/VolGroupPROD-ProdArchive
                      10313016   1693640   8095500  18% /production/archive
[casper@casperbox]:~/.wjohnson>
[casper@casperbox]:~/.wjohnson>
[casper@casperbox]:~/.wjohnson>
[casper@casperbox]:~/.wjohnson>
[casper@casperbox]:~/.wjohnson> df -k | grep -v dev
Filesystem           1K-blocks      Used Available Use% Mounted on
                      28313732   9816924  17035356  37% /
                      15481840   3495504  11199904  24% /export/home
                      15481840   1523692  13171716  11% /production
                      30963708  20410952   8979892  70% /production/log
                      10313016   1693640   8095500  18% /production/archive
[casper@casperbox]:~/.wjohnson>

From Data::Dumper - many of the hash values are coming up as undefined. is there a way that I could predefine the values of the hash. I want to learn to get rid of them.

$VAR1 = {};
Use of uninitialized value in substitution (s///) at ./get_df.just_capacity line 24.
Use of uninitialized value in division (/) at ./get_df.just_capacity line 25.
Use of uninitialized value in hash element at ./get_df.just_capacity line 17.
$VAR1 = {
          '' => {
                  'free' => undef,
                  'mount' => undef,
                  'used' => undef,
                  'name' => '/dev/mapper/VolGroup00-LogVol00',
                  'capacity' => '0',
                  'size' => undef
            }
        };
$VAR1 = {};
$VAR1 = {
          '' => {
                  'free' => undef,
                  'mount' => undef,
                  'used' => undef,
                  'name' => '/dev/mapper/VolGroup00-LogVol00',
                  'capacity' => '0',
                  'size' => undef
                },

this is resolved by using df -k | grep -v var - but there has to be a better way.

i alarmed alien
  • 9,412
  • 3
  • 27
  • 40
capser
  • 2,442
  • 5
  • 42
  • 74
  • 1
    Minor nitpick, but the line numbers in your code and in the errors are off by one. – ThisSuitIsBlackNot Dec 16 '13 at 18:48
  • 3
    Have you tried using Data::Dumper to examine what's in %info when this is running? I suspect with df, you'll find device names could get long, and force the rest of the data to be on the next line, hence the warnings about uninitialized data in the hash. Edit: Looking at the help for df, I think you may want to pass the -P option. – ratmatz Dec 16 '13 at 18:53
  • 1
    I don't get any errors when I run this on my machine, but then again `df` returns different things on each of our machines. – Hunter McMillen Dec 16 '13 at 18:56
  • 1
    I've verified that I get errors because one of my device names is rather long. – ratmatz Dec 16 '13 at 18:58
  • Someone else tackled the problem of parsing `df` output and put [their solution](http://search.cpan.org/~iguthrie/Filesys-DfPortable-0.85/DfPortable.pm) on CPAN. I haven't used it, but it might be worth a look. – ThisSuitIsBlackNot Dec 16 '13 at 19:07
  • 2
    Re: "I looked at the DF module on CPAN...but I would have to get sysadmin approval to get it installed." [You don't need root access to install modules](http://stackoverflow.com/questions/3735836/how-can-i-install-perl-modules-without-root-privileges) (if that's the issue; I understand there can also be company policies, etc.) – ThisSuitIsBlackNot Dec 17 '13 at 15:25
  • I have to make a case with the sysadmins - "waht is the business reason we need to install this module on this machine" – capser Dec 17 '13 at 23:51

3 Answers3

5

perldiag:

An undefined value was used as if it were already defined. It was interpreted as a "" or a 0, but maybe it was a mistake. To suppress this warning assign a defined value to your variables.

To help you figure out what was undefined, perl will try to tell you the name of the variable (if any) that was undefined. In some cases it cannot do this, so it also tells you what operation you used the undefined value in. Note, however, that perl optimizes your program anid the operation displayed in the warning may not necessarily appear literally in your program. For example, "that $foo" is usually optimized into "that " . $foo , and the warning will refer to the concatenation (.) operator, even though there is no . in your program.

In short, you used a variable as if it contained a string or number, but its value was undef, perhaps because it never received a value or because it doesn't exist.

Perhaps you are using the wrong variable name. Perhaps you need to provide a default. The causes are innumerable, so there's no single fix.

Community
  • 1
  • 1
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 1
    This should be in some kind of a FAQ on SO somewhere (much like [What's the easiest way to install a missing Perl module?](http://stackoverflow.com/questions/65865/whats-the-easiest-way-to-install-a-missing-perl-module)) – ThisSuitIsBlackNot Dec 16 '13 at 19:04
1

Let's concentrate on the first warning. Somewhere around lines 20/21, you get an undef warning. As as already been pointed out, either you've specified a non-existent variable (mispelling?) or the variable was never initialized.

There is nothing wrong with leaving a variable unitialized, as long as you test to see if it's uninitialized.

I use a lot of hash structures, and instantiate them:

my %test_data;

If my logic has somehow branched around filling this hash, then when I go to use %test_data, I first test to see if it is set to undef.

if(%test_data)
{
  <do something using the hash>;
}

In your case, you set $percentage to a value, but it appears $percentage is set to undef. $percentage =~ s{%}{};

So, before you get to that line, you need to branch around it if !$percentage.

octopusgrabbus
  • 10,555
  • 15
  • 68
  • 131
1

Your code seems to work fine for me (running Perl 5.14.2 on Ubuntu 13.10).

I suspect that the problem is that the df command on your machine isn't returning data in the same format as the code expects.

Dave Cross
  • 68,119
  • 3
  • 51
  • 97