Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl foreach loop prints only one line

Tags:

foreach

perl

I have this Perl code that is only printing the first line instead of all the lines.

use Net::SSH::Perl;
my $user = "user"; 
my $cmd = "df -m | grep data";
my $host = "host1.example.com"; 

my $ssh = Net::SSH::Perl->new($host);
$ssh->login($user);
my ($dflines,$errors,$exit) = $ssh->cmd($cmd);
foreach $line ($dflines) {
  print "$line";
  my @values = split(' ',$line);
  my ($MBsize, $MBused, $MBavail, $dir) =
      ($values[1], $values[2], $values[3], $values[5]);
  print "MBsize=$MBsize MBused=$MBused MBavail=$MBavail dir=$dir\n";
}

It prints:

/dev/sdb1              1407118    931813    403828  70% /data1
/dev/sdc1              1407118    921739    413902  70% /data2
/dev/sdd1              1407118    909408    426233  69% /data3
/dev/sde1              1407118    918828    416813  69% /data4
/dev/sdf1              1407118    922335    413306  70% /data5
MBsize=1407118 MBused=931813 MBavail=403828 dir=/data1

I would expect:

/dev/sdb1              1407118    931813    403828  70% /data1
/dev/sdc1              1407118    921739    413902  70% /data2
/dev/sdd1              1407118    909408    426233  69% /data3
/dev/sde1              1407118    918828    416813  69% /data4
/dev/sdf1              1407118    922335    413306  70% /data5
MBsize=1407118 MBused=931813 MBavail=403828 dir=/data1
MBsize=1407118 MBused=921739 MBavail=413902 dir=/data2
MBsize=1407118 MBused=909408 MBavail=426233 dir=/data3
MBsize=1407118 MBused=918828 MBavail=416813 dir=/data4
MBsize=1407118 MBused=922335 MBavail=413306 dir=/data5

I'm almost certain it's something basic. Any help is appreciated. Thanks!

like image 643
senile_genius Avatar asked Jan 24 '12 04:01

senile_genius


People also ask

What is the difference between for loop and for each loop in Perl?

There is no difference. From perldoc perlsyn: The foreach keyword is actually a synonym for the for keyword, so you can use foreach for readability or for for brevity. Save this answer.

Which can be correct syntax of foreach in Perl?

A foreach loop is used to iterate over a list and the variable holds the value of the elements of the list one at a time. It is majorly used when we have a set of data in a list and we want to iterate over the elements of the list instead of iterating over its range.

How do I end a foreach loop in Perl?

In many programming languages you use the break operator to break out of a loop like this, but in Perl you use the last operator to break out of a loop, like this: last; While using the Perl last operator instead of the usual break operator seems a little unusual, it can make for some readable code, as we'll see next.


1 Answers

The problem is this line:

foreach $line ($dflines) {

You are only executing one iteration, since that is not an array, but a scalar. When you print "$line" it actually prints all of the lines that you captured, but I guess it looks like you printed many values in a loop. In the subsequent part:

my @values = split(' ',$line);
my ($MBsize, $MBused, $MBavail, $dir) = 
        ($values[1], $values[2], $values[3], $values[5]);
print "MBsize=$MBsize MBused=$MBused MBavail=$MBavail dir=$dir\n";

You only use the first few values of the split, but the rest of that line is in there as well. In other words, @values contains all of the values you expect. Range 0..5 contains the first row, 6..10 the next, and so on. Since you only use the first 6 values, you don't see them.

A quick fix might be to do:

foreach $line (split /\n/, $dflines) {

Which would break up your input the way you were expecting it to be.

Some tips:

Always use warnings; use strict;

And you should make use of some proper perl features:

for my $line (split /\n/, $dflines) {
   print $line;
   my @values = split ' ', $line;
   printf "MBsize=%s MBused=%s MBavail=%s dir=%s\n", @values[1,2,3,5];
}

It looks like you want to print the MBsize ... lines after the regular output. If so, you can just store the lines in an array and print after the loop:

my @print;
for my $line (split /\n/, $dflines) {
   print $line;
   my @values = split ' ', $line;
   push @print, sprintf "MBsize=%s MBused=%s MBavail=%s dir=%s\n", @values[1,2,3,5];
}   # note  ----^ sprintf instead
print @print;
like image 85
TLP Avatar answered Oct 15 '22 16:10

TLP