Megiddo Megiddo - 1 month ago 5
Perl Question

Perl, reading text files, saving columns for using elements of columns to open other files

I have a text file, tab separated, as follows:


< this is a header

col1 col2 col3

blablabla text1.txt blablabla

blablabla text2.txt blablabla

blablabla text3.txt blablabla


I want to be able to extract certain elements (columns), in this case only the words text1.txt, text2.txt and text3.txt. I want to use them later to open the files with those names.
So far I have the code:

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

my @fields;
my ($column1, $column2, $column3);

my $text = "text.txt";

open(FILE, $text) or die "Could not read from $text, program halting.";

my @files;

while(<FILE>)
{
chomp;
/^</ and next;
/^\s*$/ and next;
/line*/ and next;

($column1, $column2, $column3) = split('\s', $_);

#PRINT ONE
#print $column2, "\t";


}
#PRINT TWO
print $column2, "\t";

close FILE;


If I do the print as commented with #PRINT ONE, I get the correct version as an output only,with all three elements but when I try to save it in another variable or write it to file, only "text3.txt" remains.
If I do the print as in #PRINT TWO, I only get one element, the same text3.txt.
How do I learn from this? I have tried lots of codes from this site but no result so far.Thank you.

Answer Source

This is happening because you overwrite $column2 on every pass of the loop, then after you leave the loop, you have the very last result (text3.txt).

You can write to a file within the loop, which this example shows. It also shows how to use the proper 3-arg open, with lexical file handles:

use warnings;
use strict;

my $input_file = 'data.txt';
my $output_file = 'out.txt';

open my $fh, '<', $input_file or die $!;
open my $wfh, '>', $output_file or die $!;

while (<$fh>){
    chomp;
    next if /^\</;
    next if /^\s*$/;

    my ($c1, $c2, $c3) = split /\s/, $_;

    print $wfh "$c2\n";
}

Given this as the input file:

< this is a header

col1 col2 col3
blablabla text1.txt blablabla
blablabla text2.txt blablabla
blablabla text3.txt blablabla

Produces:

col2
text1.txt
text2.txt
text3.txt

...in the output file. You'll have to sort out how to filter the first line.

You can also save the output to an array within the loop, then work on it later:

use warnings;
use strict;

my $input_file = 'data.txt';

open my $fh, '<', $input_file or die $!;

my @saved_entries;

while (<$fh>){
    chomp;
    next if /^\</;
    next if /^\s*$/;
    push @saved_entries, (split /\s/, $_)[1];
}

for (@saved_entries){
    print "$_\n";
}

...which you can then write to a file or do what you need to with.

Note that I'm being overly verbose here, as to be as close to OP code as possible.