Facing issue using map function in perl - perl

I have the below lines:
7290741.out:Info: /test doesn't exist, Running on Network location
7300568.out:sh: /tmp/test/1234_123_test/test1/test2/abc.txt: bad interpreter
I have these lines in an array #test1.
I want to fetch only the numbers before .out and put them in an array #test2.
I used the below code for this:
foreach my $test1(#test1) {
my #test2;
map { /(d+)\.out/ and push #test2, $1 } <$error>;
print "#test2\n";
}
But, when I execute the code, it is printing complete lines, and I want the output like below:
7290741
7300568
Can someone please help?

When I ran your code, I just got 2 blank lines of output.
Regardless, here is a simpler version of your code which just prints out the numbers:
use warnings;
use strict;
my #test1;
while (<DATA>) {
chomp;
push #test1, $_;
}
my #test2;
for (#test1) {
push #test2, $1 if /(\d+)\.out/;
}
for (#test2) {
print "$_\n";
}
__DATA__
7290741.out:Info: /test doesn't exist, Running on Network location
7300568.out:sh: /tmp/test/1234_123_test/test1/test2/abc.txt: bad interpreter
There are numerous problems with your code.
You should use warnings and strict.
The $error variable was not defined in the code you posted.
d in the regular expression should have been \d.
You should have declared the #test2 variable outside the foreach loop; otherwise, it would only have a single value due to variable scoping.

my #nums = map { /^(\d+)\.out/ } <$errors>
Is the simplest way to put it, using map. When you try to first read the errors into an array (#test1) and loop around those values, and inside the loop try to read the values again, you are doing the same thing twice. map is also a loop.
This is assuming that your file with errors is what the filehandle $errors is reading from. Remember also to always use
use strict;
use warnings;

Perhaps OP is looking for solution of following form
Explanation:
<DATA> in this context will represent an array of lines
map will form a loop through lines
regex extracts portion of information OP interested in
result is stored in #test array
NOTE: Data::Dumper is used only for the result visualization
#!/usr/bin/env perl
#
# vim: ai ts=4 sw=4
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my #test = map { /^(.*?).out/ } <DATA>;
say Dumper(\#test);
__DATA__
7290741.out:Info: /test doesn't exist, Running on Network location
7300568.out:sh: /tmp/test/1234_123_test/test1/test2/abc.txt: bad interpreter
Output
$VAR1 = [
'7290741',
'7300568'
];

Related

How to print rows information from two dimensional array in Perl?

I have the following two dimensional array (file.txt):
Code Element Repetitions
AL Train 23
BM Car 30
CN Bike 44
From an input (Code) given by the user, I want to extract the
corresponding Element information.
Example input: BM
Example output:Car
I tried with this code but I do not know how to compare the input name with array content. Thank you a lot
#!/usr/bin/perl
use strict;
use warnings;
print("Type code: ");
my $code = <STDIN>;
chomp($code);
my #content;
if(!open(TABLET, "file.txt")){
die "Unable to open the file\n";
}
while(<TABLET>){
chomp;
push #content, [split / /];
}
foreach my $row ($content) {
if ($content{$code}) {
print "$content{$code}\n";
}
}
close(TABLET);
There are a few problems here. And they can mostly be found by adding use strict to your code. The vast majority of experienced Perl programmers will always start their programs with:
use strict;
use warnings;
as these additions will find a huge number of common mistakes that programmers are prone to make.
The first problem can't be found like that. It seems to be a typo. You split your input using split /;+/ but your input file seems to be delimited by whitespace. So change split /;+/ to just split.
Now let's add use strict to your code and see what happens.
$ perl 2d
Global symbol "$content" requires explicit package name (did you forget to declare "my $content"?) at 2d line 20.
Global symbol "%content" requires explicit package name (did you forget to declare "my %content"?) at 2d line 21.
Global symbol "%content" requires explicit package name (did you forget to declare "my %content"?) at 2d line 22.
Execution of 2d aborted due to compilation errors.
Although there are three errors listed here, the second and third ones are both the same. But let's start with the first. Line 20 in my program is:
foreach my $row ($content) {
But what's that $content variable? You don't use that anywhere else. I suspect it's a typo for #content. Let's change that and try again.
$ perl 2d
Global symbol "%content" requires explicit package name (did you forget to declare "my %content"?) at 2d line 21.
Global symbol "%content" requires explicit package name (did you forget to declare "my %content"?) at 2d line 22.
Execution of 2d aborted due to compilation errors.
Ok. That fixed the first problem, but I guess we now have to look at the repeated error. This is generated by lines 21 and 22, which look like this:
if ($content{$code}) {
print "$content{$code}\n";
Obviously, there's no mention of %content on either of those lines - so what's the problem?
Well, the problem is that %content is mentioned on both of those lines, but it's disguised as $content{$code} in both cases. You have an array called #content and you'd look up values in that array using syntax like $content[0]. The face that you're using {...} instead of [...] means that you're looking in %content, not #content (in Perl you're allowed to have an array and a hash - and also a scalar - all with the same name, which is always a terrible idea!)
But we can't just change $content{$code} to $content[$code] because $code is string ("BM") and array indexes are integers. I we need to rethink this from scratch and actually store the data in %content, not #content. And, actually, I think that makes the code simpler.
#!/usr/bin/perl -w
use strict;
use warnings;
print("Type code: ");
my $code = <STDIN>;
chomp($code);
my %content;
if (!open(TABLET, "file.txt")){
die "Unable to open the file\n";
}
while(<TABLET>){
chomp;
my #record = split;
$content{$record[0]} = \#record;
}
if (exists $content{$code}) {
print "$content{$code}[1]\n";
} else {
print "$code is not a valid code\n";
}
close(TABLET);
We can clean that up a bit (for example, by using lexical filehandles and the three-arg version of open()) to get this:
#!/usr/bin/perl
use strict;
use warnings;
print("Type code: ");
chomp( my $code = <STDIN> );
my %content;
open my $tablet_fh, '<', 'file.txt'
or die "Unable to open the file\n";
while(<$tablet_fh>){
chomp;
my #record = split;
$content{$record[0]} = \#record;
}
if (exists $content{$code}) {
print "$content{$code}[1]\n";
} else {
print "$code is not a valid code\n";
}

Perl syntax error printing list index

I am trying to print an index of a list returned from a function call. I am wrapping the function call in parenthesis in an attempt to convert the list to an array. The program fails to compile saying 'syntax error at file.pl line 4, near ")["'. If I create a temporary variable $a or use printf indexing is fine. Why does print brake, is there a better alternative?
sub get{
return (1,2);
}
#print (get())[0]; #fails
printf("%d",(get())[0]);
my $a = (get())[0];
print $a;
I assume that you are foolishly not using
use warnings;
Which is quite a bad thing to not do. If you had used it, you would get the warning:
print (...) interpreted as function
Which is to say, what you wrote
print (get())[0]
Is something Perl interprets as you trying to put a subscript on the print() function. This does not work.
For the code to do what you expect, you need to be explicit about the parentheses:
print ( (get())[0] );
You should always use
use strict;
use warnings;
There is a slight learning curve to using these, but they only show you your errors. Not using them only hides your errors, and your code does not work better.
Try this :
sub get{
return (1,2);
}
print((get)[0]);
or
my $a = (get)[0];
print $a;
OUTPUT
1

Using # and $ with the same variable name in Perl

I am declaring the same variable name with # and $:
#ask=(1..9);
$ask="insanity";
print ("Array #ask\n");
print ("Scalar $ask\n");
Without using use strict I am getting output correctly but when I am using use strict it gives me a compilation error.
Do these two variables refer to two different memory locations or is it the same variable?
You've got two variables:
#ask
$ask
You could have %ask (a hash) too if you wanted. Then you'd write:
print $ask, $ask[0], $ask{0};
to reference the scalar, the array and the hash.
Generally, you should avoid this treatment, but the variables are all quite distinct and Perl won't be confused.
The only reason use strict; is complaining is because you don't prefix your variables with my:
#!/usr/bin/env perl
use strict;
use warnings;
my #ask = (1..9);
my $ask = "insanity";
my %ask = ( 0 => 'infinity', infinity => 0 );
print "Array #ask\n";
print "Scalar $ask\n";
print "Hash $ask{0}\n";
with use strict; you need to declare your variables first before using it.
For example:
use strict;
my #ask=(1..9);
my $ask="insanity";
print ("Array #ask\n");
print ("Scalar $ask\n");
#ask and $ask are different variables — as is %ask — and it is not an error to do this. It is however poor style.
Because the sigil changes when you use them, such as when you use $ask[1] to get the second element of #ask, the code becomes harder to read and use strict will also not be able to tell if you've gotten confused. Thus it's a good idea to use names that differ in more than the sigil unless you know what you're doing. So you could use e.g. #asks and $ask.
The error you are getting with strict is not due to variable names. It is because you are not declaring the variables (using one of my, our, local, or state. Nor are you using the vars pragma.
Short answer: Stick a my in front of each variable, and you'll be strict-compliant.
For package variables, you can examine entries in the symbol table. $ask and #ask are separate entities:
#!/usr/bin/env perl
use Devel::Symdump;
use YAML;
#ask=(1..9);
$ask="insanity";
my $st = Devel::Symdump->new('main');
print Dump [ $st->$_ ] for qw(
scalars
arrays
);
Among other things, this code will output:
--
…
- main::ask
…
---
…
- main::ask
…
Being able to use the same name can help when, say, you have an array of fish and you are doing something with each fish in the array:
for my $fish (#fish) {
go($fish);
}
Normally, it is more expressive to use the plural form for arrays and hashes, the singular form for elements of an array, and something based on the singular form for keys in a hash:
#!/usr/bin/env perl
use strict;
use warnings;
my #ships = ('Titanic', 'Costa Concordia');
my %ships = (
'Titanic' => {
maiden_voyage => '10 April 1912',
capacity => 3_327,
},
'Costa Concordia' => {
maiden_voyage => '14 July 2006',
capacity => 4_880,
},
);
for my $ship (#ships) {
print "$ship\n";
}
while (my ($ship_name, $ship_details) = each %ships) {
print "$ship_name capacity: $ship_details->{capacity}\n";
}

perl print array from subroutine

#! /usr/local/bin/perl
sub getClusters
{
my #clusters = `/qbo/bin/getclusters|grep -v 'qboc33'`;
chomp(#clusters);
return \#clusters;
}
ummm okay .. how do I get at this array to print since ...
foreach $cluster (getClusters())
{ print $cluster."\n"; }
doesn't seem to work.
Thanks.
You are returning a reference, and not dereferencing it anywhere.
foreach $cluster (#{getClusters()})
OR
return #clusters;
Either should fix it (with slightly different effects), with the first one being preferred (your array is kind of big).
You'd use the non-referenced array return for limited number of elements, usually for the purpose of multi-return (thus, usually, limited to 2 or 3, known-length arrays).
If you ran your program under use strict; use warnings;, it would have told you why it failed. As Amadan said, you need to dereference the reference you return.
Perl Solution
#!/usr/local/bin/perl
use strict;
use warnings;
main();
sub main{
{
local $" = "\n";
print "#{getClusters()}";
}
}
sub getClusters{
my #tArray = `/qbo/bin/getclusters|grep -v 'qboc33'`;
chomp #tArray;
return \#tArray;
}
Notice
You don't need a foreach loop for debugging, you can just reset the $" operator however to separate array elements however you like (eg, , , , or how I set it in the code above \n).
Returning an array ref is a plus, don't send back the full array (good job)
use strict/warnings, especially when debugging
try to avoid system calls using ``
To make it easy, you can first receive the return value and then print it like
use strict;
use warning;
my $cluster_array = getClusters();
my #cluster_return = #{$cluster_array};
foreach my $cluster(#cluster_return){
print"$cluster\n";
}

What's an easy way to print a multi-line string without variable substitution in Perl?

I have a Perl program that reads in a bunch of data, munges it, and then outputs several different file formats. I'd like to make Perl be one of those formats (in the form of a .pm package) and allow people to use the munged data within their own Perl scripts.
Printing out the data is easy using Data::Dump::pp.
I'd also like to print some helper functions to the resulting package.
What's an easy way to print a multi-line string without variable substitution?
I'd like to be able to do:
print <<EOL;
sub xyz {
my $var = shift;
}
EOL
But then I'd have to escape all of the $'s.
Is there a simple way to do this? Perhaps I can create an actual sub and have some magic pretty-printer print the contents? The printed code doesn't have to match the input or even be legible.
Enclose the name of the delimiter in single quotes and interpolation will not occur.
print <<'EOL';
sub xyz {
my $var = shift;
}
EOL
You could use a templating package like Template::Toolkit or Text::Template.
Or, you could roll your own primitive templating system that looks something like this:
my %vars = qw( foo 1 bar 2 );
Write_Code(\$vars);
sub Write_Code {
my $vars = shift;
my $code = <<'END';
sub baz {
my $foo = <%foo%>;
my $bar = <%bar%>;
return $foo + $bar;
}
END
while ( my ($key, $value) = each %$vars ) {
$code =~ s/<%$key%>/$value/g;
}
return $code;
}
This looks nice and simple, but there are various traps and tricks waiting for you if you DIY. Did you notice that I failed to use quotemeta on my key names in the substituion?
I recommend that you use a time-tested templating library, like the ones I mentioned above.
You can actually continue a string literal on the next line, like this:
my $mail = "Hello!
Blah blah.";
Personally, I find that more readable than heredocs (the <<<EOL thing mentioned elsewhere).
Double quote " interpolates variables, but you can use '. Note you'll need to escape any ' in your string for this to work.
Perl is actually quite rich in convenient things to make things more readable, e.g. other quote-operations. qq and q correspond to " and ' and you can use whatever delimiter makes sense:
my $greeting = qq/Hello there $name!
Nice to meet you/; # Interpolation
my $url = q|http://perlmonks.org/|; # No need to escape /
(note how the syntax coloring here didn't quite keep up)
Read perldoc perlop (find in page: "Quote and Quote-like Operators") for more information.
Use a data section to store the Perl code:
#!/usr/bin/perl
use strict;
use warnings;
print <DATA>;
#print munged data
__DATA__
package MungedData;
use strict;
use warnings;
sub foo {
print "foo\n";
}
Try writing your code as an actual perl subroutine, then using B::Deparse to get the source code at runtime.