How can I read the lines of a file into an array in Perl? - perl

I have a file named test.txt that is like this:
Test
Foo
Bar
But I want to put each line in a array and print the lines like this:
line1 line2 line3
But how can I do this?

#!/usr/bin/env perl
use strict;
use warnings;
my #array;
open(my $fh, "<", "test.txt")
or die "Failed to open file: $!\n";
while(<$fh>) {
chomp;
push #array, $_;
}
close $fh;
print join " ", #array;

Here is my single liner:
perl -e 'chomp(#a = <>); print join(" ", #a)' test.txt
Explanation:
read file by lines into #a array
chomp(..) - remove EOL symbols for each line
concatenate #a using space as separator
print result
pass file name as parameter

One more answer for you to choose from:
#!/usr/bin/env perl
open(FILE, "<", "test.txt") or die("Can't open file");
#lines = <FILE>;
close(FILE);
chomp(#lines);
print join(" ", #lines);

If you find yourself slurping files frequently, you could use the File::Slurp module from CPAN:
use strict;
use warnings;
use File::Slurp;
my #lines = read_file('test.txt');
chomp #lines;
print "#lines\n";

The most basic example looks like this:
#!/usr/bin/env perl
use strict;
use warnings;
open(F, "<", "test.txt") or die("Cannot open test.txt: $!\n"); # (1)
my #lines = ();
while(<F>) { chomp; push(#lines, $_); } # (2)
close(F);
print "#lines"; # (3) stringify
(1) is the place where the file is opened.
(2) File handles work nicely within list enviroments (scalar/list environments are defined by the left value), so if you assign an array to a file handle, all the lines are slurped into the array. The lines are delimited (ended) by the value of $/, the input record separator. If you use English;, you can use $IRS or $INPUT_RECORD_SEPARATOR. This value defaults to the newline character \n;
While this seemed to be a nice idea, I've just forgot the fact that if you print all the lines, the ending \n will be printed too. Baaad me.
Originally the code was:
my #lines = <F>;
instead of the while loop. This is still a viable alternative, but you should swap (3) with chomping and then printing/stringifying all the elements:
for (#lines) { chomp; }
print "#lines";
(3) Stringifying means converting an array to a string and inserting the value $" between the array elements. This defaults to a space.
See: the perlvar page.
So the actual 2nd try is:
#!/usr/bin/env perl
use strict;
use warnings;
open(F, "<", "test.txt") or die("Cannot open test.txt: $!\n"); # (1)
my #lines = <F>; # (2)
close(F);
chomp(#lines);
print "#lines"; # (3) stringify

This is the simplest version I could come up with:
perl -l040 -pe';' < test.txt
Which is roughly equivalent to:
perl -pe'
chomp; $\ = $/; # -l
$\ = 040; # -040
'
and:
perl -e'
LINE:
while (<>) {
chomp; $\ = $/; # -l
$\ = " "; # -040
} continue {
print or die "-p destination: $!\n";
}
'

This is the code that do this (assume the below code inside script.pl) :
use strict;
use warnings
my #array = <> ;
chomp #array;
print "#array";
It is run by:
scirpt.pl [your file]

Related

perl array prints as GLOB(#x#########)

I have a file which contains a list of email addresses which are separated by a semi-colon which is configured much like this (but much larger) :
$ cat email_casper.txt
casper1#foo.com; casper2#foo.com; casper3#foo.com; casper.casper4#foo.com;
#these throw outlook error :
#casper101#foo.com ; casper100#foo.com
#cat /tmp/emailist.txt | tr '\n' '; '
#cat /tmp/emallist.txt | perl -nle 'print /\<(.*)\>/' | sort
I want to break it up on the semicolon - so I suck the whole file into an array supposedly the contents are split on semicolon.
#!/usr/bin/perl
use strict;
use warnings;
my $filename = shift #ARGV ;
open(my $fh, '<', $filename) or die "Could not open file $filename $!";
my #values = split(';', $fh);
foreach my $val (#values) {
print "$val\n";
}
exit 0 ;
But the file awards me with a golb. I just don't know what is going one.
$ ./spliton_semi.pl email_casper.txt
GLOB(0x80070b90)
If I use Data::Dumper I get
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper ;
my $filename = shift #ARGV ;
open(my $fh, '<', $filename) or die "Could not open file $filename $!";
my #values = split(';', $fh);
print Dumper \#values ;
This is what the Dumper returns :
$ ./spliton_semi.pl email_casper.txt
$VAR1 = [
'GLOB(0x80070b90)'
];
You do not "suck the whole file into an array". You don't even attempt to read from the file handle. Instead, you pass the file handle to split. Expecting a string, it stringifies the file handle into GLOB(0x80070b90).
You could read the file into an array of lines as follows:
my #lines = <$fh>;
for my $line ($lines) {
...
}
But it's far simpler to read one line at a time.
while ( my $line = <$fh> ) {
...
}
In fact, there is no reason not to use ARGV here, simplifying your program to the following:
#!/usr/bin/perl
use strict;
use warnings;
use feature qw( say );
while (<>) {
chomp;
say for split /\s*;\s*/, $_;
}
This line
my #values = split(';', $fh);
is not reading from the filehandle like you think it is. You're actually calling split on the filehandle object itself.
You want this:
my $line = <$fh>;
my #values = split(';', $line);
Starting point:
#!/usr/bin/perl
use strict;
use warnings;
open(my $fh, '<', 'dummy.txt')
or die "$!";
my #values;
while (<$fh>) {
chomp;
# original
# push(#values, split(';', $_));
# handle white space
push(#values, split(/\s*;\s*/, $_));
}
close($fh);
foreach my $val (#values) {
print "$val\n";
}
exit 0;
Output for your example:
$ perl dummy.pl
casper1#foo.com
casper2#foo.com
casper3#foo.com
casper.casper4#foo.com

how to assign data into hash from an input file

I am new to perl.
Inside my input file is :
james1
84012345
aaron5
2332111 42332
2345112 18238
wayne[2]
3505554
Question: I am not sure what is the correct way to get the input and set the name as key and number as values. example "james" is key and "84012345" is the value.
This is my code:
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
my $input= $ARGV[0];
my %hash;
open my $data , '<', $input or die " cannot open file : $_\n";
my #names = split ' ', $data;
my #values = split ' ', $data;
#hash{#names} = #values;
print Dumper \%hash;
I'mma go over your code real quick:
#!/usr/bin/perl -w
-w is not recommended. You should use warnings; instead (which you're already doing, so just remove -w).
use strict;
use warnings;
Very good.
use Data::Dumper;
my $input= $ARGV[0];
OK.
my %hash;
Don't declare variables before you need them. Declare them in the smallest scope possible, usually right before their first use.
open my $data , '<', $input or die " cannot open file : $_\n";
You have a spurious space at the beginning of your error message and $_ is unset at this point. You should include $input (the name of the file that failed to open) and $! (the error reason) instead.
my #names = split ' ', $data;
my #values = split ' ', $data;
Well, this doesn't make sense. $data is a filehandle, not a string. Even if it were a string, this code would assign the same list to both #names and #values.
#hash{#names} = #values;
print Dumper \%hash;
My version (untested):
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
#ARGV == 1
or die "Usage: $0 FILE\n";
my $file = $ARGV[0];
my %hash;
{
open my $fh, '<', $file or die "$0: can't open $file: $!\n";
local $/ = '';
while (my $paragraph = readline $fh) {
my #words = split ' ', $paragraph;
my $key = shift #words;
$hash{$key} = \#words;
}
}
print Dumper \%hash;
The idea is to set $/ (the input record separator) to "" for the duration of the input loop, which makes readline return whole paragraphs, not lines.
The first (whitespace separated) word of each paragraph is taken to be the key; the remaining words are the values.
You have opened a file with open() and attached the file handle to $data. The regular way of reading data from a file is to loop over each line, like so:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my $input = $ARGV[0];
my %hash;
open my $data , '<', $input or die " cannot open file : $_\n";
while (my $line = <$data>) {
chomp $line; # Removes extra newlines (\n)
if ($line) { # Checks if line is empty
my ($key, $value) = split ' ', $line;
$hash{$key} = $value;
}
}
print Dumper \%hash;
OK, +1 for using strict and warnings.
First Take a look at the $/ variable for controlling how a file is broken into records when it's read in.
$data is a file handle you need to extract the data from the file, if it's not to big you can load it all into an array, if it's a large file you can loop over each record at a time. See the <> operator in perlop
Looking at you code it appears that you want to end up with the following data structure from your input file
%hash(
james1 =>[
84012345
],
aaron5 => [
2332111,
42332,
2345112,
18238
]
'wayne[2]' => [
3505554,
]
)
See perldsc on how to do that.
All the documentation can be read using the perldoc command which comes with Perl. Running perldoc on its own will give you some tips on how to use it and running perldoc perldoc will give you possibly far more info than you need at the moment.

My perl script isn't working, I have a feeling it's the grep command

I'm trying for search in the one file for instances of the
number and post if the other file contains those numbers
#!/usr/bin/perl
open(file, "textIds.txt"); #
#file = <file>; #file looking into
# close file; #
while(<>){
$temp = $_;
$temp =~ tr/|/\t/; #puts tab between name and id
#arrayTemp = split("\t", $temp);
#found=grep{/$arrayTemp[1]/} <file>;
if (defined $found[0]){
#if (grep{/$arrayTemp[1]/} <file>){
print $_;
}
#found=();
}
print "\n";
close file;
#the input file lines have the format of
#John|7791 154
#Smith|5432 290
#Conor|6590 897
#And in the file the format is
#5432
#7791
#6590
#23140
There are some issues in your script.
Always include use strict; and use warnings;.
This would have told you about odd things in your script in advance.
Never use barewords as filehandles as they are global identifiers. Use three-parameter-open
instead: open( my $fh, '<', 'testIds.txt');
use autodie; or check whether the opening worked.
You read and store testIds.txt into the array #file but later on (in your grep) you are
again trying to read from that file(handle) (with <file>). As #PaulL said, this will always
give undef (false) because the file was already read.
Replacing | with tabs and then splitting at tabs is not neccessary. You can split at the
tabs and pipes at the same time as well (assuming "John|7791 154" is really "John|7791\t154").
Your talking about "input file" and "in file" without exactly telling which is which.
I assume your "textIds.txt" is the one with only the numbers and the other input file is the
one read from STDIN (with the |'s in it).
With this in mind your script could be written as:
#!/usr/bin/perl
use strict;
use warnings;
# Open 'textIds.txt' and slurp it into the array #file:
open( my $fh, '<', 'textIds.txt') or die "cannot open file: $!\n";
my #file = <$fh>;
close($fh);
# iterate over STDIN and compare with lines from 'textIds.txt':
while( my $line = <>) {
# split "John|7791\t154" into ("John", "7791", "154"):
my ($name, $number1, $number2) = split(/\||\t/, $line);
# compare $number1 to each member of #file and print if found:
if ( grep( /$number1/, #file) ) {
print $line;
}
}

I have a file that I want to split using pipe as delimiter. How can I read the file using Perl?

Here is a shell script reading the file.
#!/bin/sh
procDate=$1
echo "Date $procDate"
file=`cat filename_$procDate.txt`
echo "$file"
I want to convert it to Perl and use the split operator with pipe | as delimiter.
It's far from clear from your question what it is that you want to do with these fields once you have split them
Your own shell script uses cat to copy the entire contents of your file into $file, but that's unlikely to be what you need to do
A very generalised Perl program would look like this
use strict;
use warnings 'all';
my ($procDate) = #ARGV;
print "Date $procDate\n";
open my $fh, '<', "filename_$procDate.txt" or die $!;
while ( <$fh> ) {
chomp;
my #fields = split /\|/;
# do something with #fields, for instance
print "#fields\n";
}
That code splits each line on pipe | characters, puts the list of substrings in #fields and then prints it separated by spaces. But I can't guess what more you might want to do?
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
open(FILE, "<filename_$procDate.txt") or die "Couldn't open file filename_$procDate.txt, $!";
while ( my $line = <FILE> ) {
print "Line content is $line\n";
my #line_content = split(/\|/, $line);
print Dumper (\#line_content);
}
close (FILE);

How to read specific lines from file and store in an array using perl?

How can i read/store uncommented lines from file into an array ?
file.txt looks like below
request abcd uniquename "zxsder,azxdfgt"
request abcd uniquename1 "nbgfdcbv.bbhgfrtyujk"
request abcd uniquename2 "nbcvdferr,nscdfertrgr"
#request abcd uniquename3 "kdgetgsvs,jdgdvnhur"
#request abcd uniquename4 "hvgsfeyeuee,bccafaderryrun"
#request abcd uniquename5 "bccsfeueiew,bdvdfacxsfeyeueiei"
Now i have to read/store the uncommented lines (first 3 lines in this script) into an array. is it possible to use it by pattern matching with string name or any regex ? if so, how can i do this ?
This below code stores all the lines into an array.
open (F, "test.txt") || die "Could not open test.txt: $!\n";
#test = <F>;
close F;
print #test;
how can i do it for only uncommented lines ?
If you know your comments will contain # at the beginning you can use
next if $_ =~ m/^#/
Or use whatever variable you have to read each line instead of $_
This matches # signs at the beginning of the line.
As far as adding the others to an array you can use push (#arr, $_)
#!/usr/bin/perl
# Should always include these
use strict;
use warnings;
my #lines; # Hold the lines you want
open (my $file, '<', 'test.txt') or die $!; # Open the file for reading
while (my $line = <$file>)
{
next if $line =~ m/^#/; # Look at each line and if if isn't a comment
push (#lines, $line); # we will add it to the array.
}
close $file;
foreach (#lines) # Print the values that we got
{
print "$_\n";
}
You could do:
push #ary,$_ unless /^#/;END{print join "\n",#ary}'
This skips any line that begins with #. Otherwise the line is added to an array for later use.
The smallest change to your original program would probably be:
open (F, "test.txt") || die "Could not open test.txt: $!\n";
#test = grep { $_ !~ /^#/ } <F>;
close F;
print #test;
But I'd highly recommend rewriting that slightly to use current best practices.
# Safety net
use strict;
use warnings;
# Lexical filehandle, three-arg open
open (my $fh, '<', 'test.txt') || die "Could not open test.txt: $!\n";
# Declare #test.
# Don't explicitly close filehandle (closed automatically as $fh goes out of scope)
my #test = grep { $_ !~ /^#/ } <$fh>;
print #test;