dplatt
dplatt

Reputation: 79

Perl: Split up variable from system output (df -lh)

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.

Upvotes: 0

Views: 568

Answers (3)

Borodin
Borodin

Reputation: 126722

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 )

Upvotes: 3

dplatt
dplatt

Reputation: 79

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!

Upvotes: 0

Sobrique
Sobrique

Reputation: 53478

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.

Upvotes: 1

Related Questions