Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Perl like awk to cut fields

Tags:

perl

I am new to perl and am attempting to extract data from a file like I would with awk. I have gathered the data from the file and stored it in the array "array". I want to grab the only certain columns and only certain rows. For example, I want to only select the index of 7 (Q) and select the three numbers to eventually make a subroutine to average them out. I also want to be able to grab just a single field from say D for the date. There are very easy ways to do this with awk and cut, but I am having a very difficult time figuring out how to do this with Perl.

Here is the data.txt file
F gge0001x gge0001y gge0001z
D 12-30-2006 12-30-2006 12-30-2006
T 14:15:20 14:15:55 14:16:27
S a69 a69 a69
B 15.8 16.1 15
M gge06001 gge06001 gge06001
P 30.1 29.6 29.9
Q 20.2 22.3 23.4

I can get it to where I can select the index that I want, I just cant cut the fields

Performance Data
Q 20.2 22.4. 23.4

Here is my code so far...

use constant;
use strict;
use warnings;
use diagnostics;

my $my_file = 'data.txt';
my @array;

open my $fh, '<', 'data.txt'
        or die "Cant open : ";

printf ("%10s", "Performance Data\n");

while(<$fh>)
{

        if( /\bF|T|B|P|Q|R|H|O|C|K|W|L\b/)
        {
                push @array, $_;

        }
}


my @tab = split(/\s+/, $array[2]);
print $tab[-2], [-3],  "\n";

Thank you for you help

like image 556
Ububtunoob Avatar asked Nov 20 '25 05:11

Ububtunoob


2 Answers

You can do it as oneliner, for example as:

perl -lanE 'print "@F[1,2,3]" if $F[0] eq "Q"' < data.txt

prints

20.2 22.3 23.4

for the meaning of the switches see prelrun.

Or using script - one pass:

use strict;
use warnings;
use feature 'say';
use Data::Dumper;

while(<>) {
    chomp;
    my @cols = split /\s+/;
    if( $cols[0] eq 'Q' ) {
        say "for Q: @cols[1,2,3]";
    }
}

Use it as perl script.pl < data.txt (redirection). It prints

for Q: 20.2 22.3 23.4

If you want load the whole "matrix" beforehand

use strict;
use warnings;
use feature 'say';
#use Data::Dumper;

my $matrixref;
while(<>) {
    chomp;
    push @$matrixref, [split /\s+/];
}
#say Dumper $matrixref;

for my $lineref (@$matrixref) {
    if( $lineref->[0] eq 'Q' ) {
        say "for Q: @$lineref[1,2,3]";
    }
}

again, using the perl script.pl < data.txt prints:

for Q: 20.2 22.3 23.4

Of course, you can change the while(<>) to while(<$fh>) and open the file internally... etc.

like image 64
jm666 Avatar answered Nov 22 '25 17:11

jm666


I think the easiest way is to split each line at space characters and then put them into a hash with the first column as key and the remaining 3 columns as value (in an array ref):

#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;

# hash which gets filled with { 'Q' => [ 20.2, 22.3, 23.4 ], ... }
my %data;

while( <DATA> ) {
    my @col = split(' ', $_ );
    $data{ $col[0] } = [ $col[1], $col[2], $col[3] ];
}

print Data::Dumper::Dumper(\%data);

__DATA__
F gge0001x gge0001y gge0001z
D 12-30-2006 12-30-2006 12-30-2006
T 14:15:20 14:15:55 14:16:27
S a69 a69 a69
B 15.8 16.1 15
M gge06001 gge06001 gge06001
P 30.1 29.6 29.9
Q 20.2 22.3 23.4

Output (reduced):

$VAR2 = {
  'B' => [
    '15.8',
    '16.1',
    '15'
  ],
  'D' => [
    '12-30-2006',
    '12-30-2006',
    '12-30-2006'
  ],
  ...
  'Q' => [
    '20.2',
    '22.3',
    '23.4'
  ],
  ...
};

Now you can access the values for Q like this:

my $first  = $data{'Q'}[0];
my $second = $data{'Q'}[1];
my $third  = $data{'Q'}[2];

This assumes that you have only one row starting with Q.

like image 32
PerlDuck Avatar answered Nov 22 '25 18:11

PerlDuck



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!