0

I've managed to use back-ticks to store my df -lh command as a variable, $var, but I would like to split it up so that each part of the variable can be assigned to another variable.

Here is my output when I print $var:

Filesystem     Size   Used  Avail Capacity  iused     ifree %iused  Mounted on
/dev/disk0s2  931Gi   82Gi  849Gi     9% 21503280 222477462    9%   /
/dev/disk1s2   19Gi  5.0Gi   14Gi    27%  1303373   3579438   27%   /Volumes/Install OS X Yosemite
/dev/disk1s3  1.8Ti  174Gi  1.6Ti    10% 45714072 437656799    9%   /Volumes/store

What I would like is to remove the first line of headers, then split it down into the following categories of:

$filesystem, $size, $used, $avail, $cap, $mounted.

I've tried using shift to get rid of the first line, but I am aware now that this is only for arrays. For a different array I have, I use chomp, i.e.

foreach my $line (@output) {
              chomp $line;
              my( $filesystem, $size, $used, $avail, $cap, $mounted ) = split (/\s+/, $line);
}

But as this is not an array, I don't know how to go about it, unless there is a way to store my system output as an array?

Many thanks.

dplatt
  • 79
  • 1
  • 10
  • 1
    "I am aware now that this is only for arrays". But you **can** store the results from backticks in an array. – Dave Cross May 19 '16 at 10:14
  • 1
    The `-h` option for `df` means *human-readable*. Since this is for computer consumption I suggest you use `df -l` instead, to remove all the formatting characters like `K`, `M` and `G` that we real people like – Borodin May 19 '16 at 10:45
  • Good shout, cheers @Borodin, saved me some trouble there, was ending up pulling off the last digits otherwise! – dplatt May 19 '16 at 10:52
  • @DaveCross, have stored in an array now, don't know why I didn't think of that. Thank you for your suggestions! – dplatt May 19 '16 at 10:52
  • dup? http://stackoverflow.com/q/6350466/632407 and check https://metacpan.org/pod/Filesys::Df – clt60 May 19 '16 at 10:58

3 Answers3

3

Yes, shift does work on arrays. But backticks in list context will return a list of lines output by the command. You can assign that list to an array and then shift the header line off the beginning

Here's an example of what you might write, and the output when I run it on my VBox system. All I do with the fields is print their values as you haven't mentioned what you might want to do with them

use strict;
use warnings 'all';
use feature 'say';

my @df = `df -l`;

shift @df;
chomp @df;

for ( @df ) {
    my ( $filesystem, $size, $used, $avail, $cap, $mounted ) = split ' ', $_, 6;
    say "( $filesystem, $size, $used, $avail, $cap, $mounted )";
}

output

( udev, 1004960, 0, 1004960, 0%, /dev )
( tmpfs, 204852, 6264, 198588, 4%, /run )
( /dev/sda1, 49409840, 4925512, 41951416, 11%, / )
( tmpfs, 1024260, 132, 1024128, 1%, /dev/shm )
( tmpfs, 5120, 4, 5116, 1%, /run/lock )
( tmpfs, 1024260, 0, 1024260, 0%, /sys/fs/cgroup )
( tmpfs, 204852, 52, 204800, 1%, /run/user/1000 )
( /dev/sr0, 56782, 56782, 0, 100%, /media/rob/VBOXADDITIONS_5.0.18_106667 )
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • I'd suggest you also use the `-P` switch (POSIX-output) to `df`: if filesystem names are long enough, `df` might else split the output into two lines ([shown here](http://askubuntu.com/q/55702/504066)) which makes them harder to parse. `-P` guarantees _"one line of information for each specified file system"_. Note that the output will then _not_ contain the inode columns (as in the OP). – PerlDuck May 19 '16 at 15:07
1

How about using a hash slice approach?

#!/usr/bin/env perl
use strict;
use warnings;

use Data::Dumper;

chomp ( my @header = split ' ', <DATA>, 9 ); 

my @rows; 
while ( <DATA> ) { 
   chomp; 
   my %this_row;
   push @rows, \%this_row;
   @this_row{@header} = split ' ', $_, 9; 
   print Dumper \%this_row;
}

print Dumper \@rows; 


foreach my $row ( @rows ) { 
   print $row -> {Filesystem}, " => ", $row -> {Size},"\n";
}


__DATA__
Filesystem     Size   Used  Avail Capacity  iused     ifree %iused  Mounted on
/dev/disk0s2  931Gi   82Gi  849Gi     9% 21503280 222477462    9%   /
/dev/disk1s2   19Gi  5.0Gi   14Gi    27%  1303373   3579438   27%   /Volumes/Install OS X Yosemite
/dev/disk1s3  1.8Ti  174Gi  1.6Ti    10% 45714072 437656799    9%   /Volumes/store

We specify a count to split, because it looks like it's only your last field that contains spaces. (Otherwise you'd have another column 'on' and that 'Install OS X Yosemite' would get split too).

This builds a data structure like this:

$VAR1 = [
          {
            'Filesystem' => '/dev/disk0s2',
            'Mounted on' => '/',
            'Avail' => '849Gi',
            '%iused' => '9%',
            'Size' => '931Gi',
            'iused' => '21503280',
            'Capacity' => '9%',
            'Used' => '82Gi',
            'ifree' => '222477462'
          },
          {
            'Capacity' => '27%',
            'iused' => '1303373',
            'Size' => '19Gi',
            '%iused' => '27%',
            'Filesystem' => '/dev/disk1s2',
            'Mounted on' => '/Volumes/Install OS X Yosemite',
            'Avail' => '14Gi',
            'ifree' => '3579438',
            'Used' => '5.0Gi'
          },
          {
            'ifree' => '437656799',
            'Used' => '174Gi',
            'Capacity' => '10%',
            'iused' => '45714072',
            '%iused' => '9%',
            'Size' => '1.8Ti',
            'Avail' => '1.6Ti',
            'Mounted on' => '/Volumes/store',
            'Filesystem' => '/dev/disk1s3'
          }
        ];

Which is an array of hashes. (e.g. each value is 'keyed').

But you could do something similar where you just split the values into an array instead.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
  • Different way of looking at it! Definitely interested in hashes, will try and incorporate this in another aspect of my code, thank you. – dplatt May 19 '16 at 10:53
0

My finished code:

 my @var= `df -l`;
      my $local_id = 2;
      shift @var; ## REMOVE TOP LINE
      foreach my $line (@var) {
          chomp $line;
          my( $filesystem, $size, $used, $avail, $cap, $mounted ) = split (/\s+/, $line);
          ## DIRTY QUICK WAY TO PULL OFF %
          $cap = substr($cap, 0, -1);
}

Df -l does not get rid of the % of capacity, so got rid of that in order to add it into my db. Stored as an array. Thanks everyone for your help and comments!

dplatt
  • 79
  • 1
  • 10
  • 1
    Okay, so why did you ask for help with this? – Borodin May 19 '16 at 10:59
  • Didn't realise you could store as an array! – dplatt May 19 '16 at 12:05
  • That's fine, but I don't see why you wanted to publish a solution of your own when there is already one that says the same thing and more. Unfortunately it happens to be my own answer, but I'm not asking you to accept it, I'm just wondering whether you realise that Stack Overflow isn't a forum, but more like a wiki. It may help you to take a look at [*What should I do when someone answers my question?*](http://stackoverflow.com/help/someone-answers) – Borodin May 19 '16 at 13:11
  • Unless you're *certain* that the *mounted* field never contains whitespace, you should use `split ' ', $_, 6` as I did – Borodin May 19 '16 at 13:20