Bug with use if REGEX_COND - perl

I would like to conditional load a package if the program name is a test script ending in .t.
However, I'm running into a bug where use if fails when the condition is a regex. I've tested this in Perl 5.10 and 5.16.
The following is my test script ending in .t:
#!/usr/bin/env perl
use v5.10;
BEGIN { say "\$0 is '$0'" }
use if $0 =~ /\.t\z/, 'List::Util', ('pairmap');
say "List::Util is " . ( $INC{"List/Util.pm"} ? '' : 'NOT ' ) . 'included';
Outputs:
$ ./test.t
$0 is './test.t'
List::Util is included
However, the same file with a .pl extension fails:
$ ./test.pl
$0 is './test.pl'
Can't locate pairmap.pm in #INC (#INC contains: /usr/lib64/perl5/5.10.0 /usr/lib64/perl5 /usr/local/share/perl5/x86_64-linux-thread-multi /usr/local/share/perl5 /usr/local/lib64/perl5 /usr/share/perl5 /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at /usr/share/perl5/if.pm line 13.
BEGIN failed--compilation aborted at ./test.pl line 7.
I can coerce the code into working if I double bang the regex or change it to a substr comparison:
use if !!( $0 =~ /\.t\z/ ), 'List::Util', ('pairmap');
use if substr( $0, -2 ) eq '.t', 'List::Util', ('pairmap');
Outputs:
$ ./test.pl
$0 is './test.pl'
List::Util is NOT included
Is this a known bug? If so, in what version was it fixed?

This is a bug in your code.
The argument list after use MODULE is in, well, list context.
m// in list context returns a list of captured strings if successful (or 1 if the regex contains no capturing groups), or the empty list on failure.
Thus:
use if "test.pl" =~ /\.t\z/, 'List::Util', ('pairmap');
is equivalent to
use if (), 'List::Util', ('pairmap');
(The match failed, so an empty list is returned.)
, in list context is the list concatenation operator, so this gives:
use if 'List::Util', 'pairmap';
'List::Util' is a true value, so this ultimately ends up loading pairmap.pm:
use pairmap;
The fix is to give the match scalar context:
use if scalar($0 =~ /\.t\z/), 'List::Util', 'pairmap';
(! also supplies scalar context to its operand, so !! has the same effect.)

Related

perl: Scalar found where operator expected at script

cannot find answer in Google, nor figure it out myself.
Win7 64bit
This is perl 5, version 22, subversion 3 (v5.22.3) built for MSWin32-x86-multi-thread-64int from Active State
with modules List::BinarySearch and PAR::Packer installed with cpan
Idea is to edit a text file and add numbers in sorted order. Below is a short version just to reproduce the problem.
Problem: binsearch_pos works when I run the script as pl but fails when I make a standalone EXE out of it.
Code to reproduce:
#!\usr\bin\perl
use strict;
use warnings;
use List::BinarySearch qw/binsearch_pos/;
my #numbers=(0,1,2,4,5,6);
print #numbers;
print "\n";
#numbers=searchandadd(\#numbers,3);
print #numbers;
#search right idx and add value
sub searchandadd {
my ($array, $add) = #_;
my #array = #{$array};
my #sorted = sort { $a <=> $b } #array;
my $idx = binsearch_pos { $a <=> $b } $add, #sorted;
if (0+#sorted == $idx) {
splice #sorted, $idx, 0, $add;
} else {
splice #sorted, $idx, 0, $add
if $sorted[$idx] ne $add;
}
return #sorted;
}
Expected output (from test.pl currently):
C:\Users\timo>test.pl 012456 0123456
EXE creation:
pp -o test.exe test.pl
EXE output:
C:\Users\timo>test.exe
Scalar found where operator expected at script/test.pl line 17, near "} $add"
(Missing operator before $add?) syntax error at script/test.pl line 17, near "} $add" Global symbol "$idx" requires
explicit package name (did you forget to declare "my $idx"?) at
script/test.pl line 18. Global symbol "$idx" requires explicit package
name (did you forget to declare "my $idx"?) at script/test.pl line 19.
Global symbol "$idx" requires explicit package name (did you forget to
declare "my $idx"?) at script/test.pl line 21. Global symbol "$idx"
requires explicit package name (did you forget to declare "my $idx"?)
at script/test.pl line 22.
I get same error when EXE made with perl2exe or pp. Could this be because there is some other version of binsearch_pos lurking somewhere?
I'm lost.
BR,
Timo

read data from excel in perl

I am trying to read data from excel, i have below code.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use feature 'say';
use Spreadsheet::XLSX;
use Spreadsheet::Read qw(ReadData);
my $book = ReadData ('/tmp/simple.xlsx');
say 'A1: ' . $book->[1]{A1};
my #row = Spreadsheet::Read::row($book->[1], 1);
for my $i (0 .. $#row) {
say 'A' . ($i+1) . ' ' . ($row[$i] // '');
}
my #rows = Spreadsheet::Read::rows($book->[1]);
foreach my $i (1 .. scalar #rows) {
foreach my $j (1 .. scalar #{$rows[$i-1]}) {
say chr(64+$i) . " $j " . ($rows[$i-1][$j-1] // '');
}
}
getting the error as:
Can't locate OLE/Storage_Lite.pm in #INC (#INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at /usr/local/share/perl5/Spreadsheet/ParseExcel.pm line 21.
BEGIN failed--compilation aborted at /usr/local/share/perl5/Spreadsheet/ParseExcel.pm line 21.
Compilation failed in require at /usr/local/share/perl5/Spreadsheet/XLSX.pm line 14.
BEGIN failed--compilation aborted at /usr/local/share/perl5/Spreadsheet/XLSX.pm line 14.
Compilation failed in require at read_excel.pl line 6.
BEGIN failed--compilation aborted at read_excel.pl line 6.
I have every related module. but as per error when i am going to download OLE/Storage_Lite.pm from the CPAN, page is going blank, and from metacpan below error is coming.
https://cpan.metacpan.org/authors/id/M/MS/MSCHWARTZ/OLE-Storage-0.386.tar.gz
Resolving cpan.metacpan.org... 151.101.128.249, 151.101.192.249, 151.101.64.249, ...
Connecting to cpan.metacpan.org|151.101.128.249|:443... connected.
ERROR: certificate common name “a.ssl.fastly.net” doesn’t match requested host name “cpan.metacpan.org”.
To connect to cpan.metacpan.org insecurely, use ‘--no-check-certificate’.
Try downloading the module tar zip from cpan or metacpan. Then build the module locally using any make utility(e.g.dmake). You can find more info for building module locally from here.

perl eval without block

I am learning perl eval. I understand how to use eval BLOCK, but I have came across the code below. What is the code below doing?
while(<>) {
eval;
warn $# if $#;
}
while(<>) {
This reads input, and places it in the variable $_. The input used by <> is first #ARGV (if you called your script with arguments), then STDIN (standard input).
Information on the diamond operator here.
eval;
This evaluates the line that was read, since not specifying what to evaluate looks at $_.
warn $# if $#;
This line will display the warnings that appear in $#, if there are any.
Perl's eval() builtin can take either a BLOCK or an EXPR. If it is given an EXPR that EXPR will be evaluated as a string which contains Perl code to be executed.
For example:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
eval { say "Hello, Block World!"; };
eval 'say "Hello, String World!";';
This code executes both say()s as you would expect.
$ ./evals.pl
Hello, Block World!
Hello, String World!
In general the string version of eval() is considered dangerous, especially if you allow interpolation into that string based on variables that are coming from outside your control. For exmaple:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
my $name = $ARGV[0] // 'World';
eval "say 'Hello, $name';";
This code is safe if called as so:
$ ./evals.pl Kaoru
Hello, Alex
$ ./evals.pl
Hello, World
But would be very dangerous if the user called it as:
$ ./evals.pl "Kaoru'; system 'rm -rf /"
On the other hand, in string eval()'s favour, it can be very useful as the opposite of Data::Dumper::Dumper() for turning dumped Perl code back into Perl-internal data structures. For example:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my $hashref = { a => 1, b => 2, c => 3 };
print Dumper $hashref;
my $VAR1;
my $hashref_copy = eval Dumper $hashref;
say $hashref_copy->{b};
Which, as you would expect, outputs:
$ ./evals.pl
$VAR1 = {
'c' => 3,
'b' => 2,
'a' => 1
};
2
See perldoc -f eval or http://perldoc.perl.org/functions/eval.html for more details.
As of Perl 5.16.3, there is also an evalbytes() which treats the string as a byte string rather than a character string. See perldoc -f perlunicode or http://perldoc.perl.org/perlunicode.html for more details on the difference between character strings and byte strings.
The code which you asked about explicitly:
while(<>) {
eval;
warn $# if $#;
}
Is reading in each line of either STDIN or the files specified in #ARGV, and evaluating each line of input as a line of Perl code. If that Perl code fails to compile, or throws an exception via die(), the error is warned to STDERR. perldoc -f eval has the full details of how and why eval() might set $#.
As an example of the code being called:
$ echo 'print "foo\\n";' | ./evals.pl
foo
$ echo 'print 1 + 1, "\\n";' | ./evals.pl
2
$ echo 'dfsdfsdaf' | ./evals.pl
Bareword "dfsdfsdaf" not allowed while "strict subs" in use at (eval 1) line 1, <> line 1.
$ echo 'die "dead";' | ./evals.pl
dead at (eval 1) line 1, <> line 1.

Perl converting a string into groups of 8 hex digits

I am trying to take a string, let's say "asdkljasdkjlaksjdla" and:
1. Print it in reverse order
2. convert it to hex
3. print in groups of 8 with leading 0x
So for example the string "asdkljasdkjlaksjdla" should print out like
0x616c646a
0x736b616c
0x6a6b6473
and so on.
So far I have this:
perl -e 'print unpack "H*", scalar reverse "asdkljasdkjlaksjdla"'
but I have not been able to figure out how to make the groups. Can you help?
You can do the hex conversion and splitting in one step with unpack "(H8)*":
print "0x$_\n" for unpack "(H8)*", scalar reverse "asdkljasdkjlaksjdla";
See perlpacktut for more information on this syntax.
(Ps. Strictly speaking, the scalar is unnecessary, since unpack already evaluates its second argument in scalar context. I'd rather have it there explicitly, though, so that the next person reading or editing this doesn't have to remember that detail. Feel free to remove it if you disagree.)
perl -E 'my $x= unpack "H*", scalar reverse "asdkljasdkjlaksjdla" ; say "0x$_" for ( $x =~ /(.{1,8})/g ) '
Needed another paren, and got it without the temp:
perl -E 'say "0x$_" for ( ( unpack "H*", scalar reverse "asdkljasdkjlaksjdla" ) =~ /(.{1,8})/g )'
If you have Perl 5.14.0 or later (needed for the /r modifier to s///):
perl -e 'print ((unpack "H*", reverse "asdkljasdkjlaksjdla") =~ s/.{2,8}/0x$&\n/gr)'
All the spaces are optional; all the parentheses are necessary.
Output:
0x616c646a
0x736b616c
0x6a6b6473
0x616a6c6b
0x647361

cannot run perl program: Can't locate Time/Piece.pm in #INC with perl5.8.4 and Can't locate DBI.pm in #INC with perl 5.12.3 [duplicate]

This question already has answers here:
What's the easiest way to install a missing Perl module?
(24 answers)
Closed 7 years ago.
I have Solaris 10,i am trying to run a Perl program.
I have two perl versions installed:
/usr/bin/perl of version 5.8.4
and
/usr/local/bin/perl of version 5.12.3
I have installed the DBI package (it got installed here, /usr/perl5/site_perl/5.8.4/sun4-solaris-64int/auto/DBI/.packlist),the problem I get by executing the Perl program with different perl version is (In ubuntu its working fine).
bash-3.00# perl temp.pl
Can't locate Time/Piece.pm in #INC (#INC contains: /usr/perl5/5.8.4/lib/sun4-
solaris-64int /usr/perl5/5.8.4/lib /usr/perl5/site_perl/5.8.4/sun4-solaris-64int
/usr/perl5/site_perl/5.8.4 /usr/perl5/site_perl /usr/perl5/vendor_perl/5.8.4/sun4-
solaris-64int /usr/perl5/vendor_perl/5.8.4 /usr/perl5/vendor_perl .) at
temp.pl line 4.
BEGIN failed--compilation aborted at temp.pl line 4.
bash-3.00# /usr/local/bin/perl temp.pl
Can't locate DBI.pm in #INC (#INC contains: /usr/local/lib/perl5/site_perl/5.12.3
/sun4-solaris /usr/local/lib/perl5/site_perl/5.12.3 /usr/local/lib/perl5/5.12.3/sun4-
solaris /usr/local/lib/perl5/5.12.3 /usr/local/lib/perl5/site_perl .) at temp.pl line5.
BEGIN failed--compilation aborted at temp.pl line 5.
I have tried hell lot of ways but not getting how to run my Perl program on solaris.
Could anybody help please.
Below is my program. In fact it was redefined by #Borodin. Thanks a lot to him.
use strict;
use warnings;
use Time::Piece;
use DBI;
open my $log, '<', '/opt/testlogs/test.log' or die "Unable to open log file: $!";
my ( $count_start, $count_interim, $count_stop ) = ( 0, 0, 0 );
while (<$log>) {
if (/server start/) {
$count_start++;
}
elsif (/server interim-update/) {
$count_interim++;
}
elsif (/server stop/) {
$count_stop++;
}
}
print <<END;
Start: $count_start
Interim: $count_interim
Stop: $count_stop
END
print localtime->strftime("%b %e %H:%M:%S"), "\n";
my $dbh = DBI->connect( "DBI:Pg:dbname=postgres;host=localhost", "postgres", "postgres", { 'RaiseError' => 1 } );
my $rows = $dbh->do(
"insert into radius (server_start, server_stop, server_interim)
Values ($count_start, $count_stop, $count_interim)"
);
printf "%d %s affected\n", $rows, $rows == 1 ? 'row' : 'rows';
You don't have Time::Piece installed for /usr/bin/perl, so install it.
/usr/bin/perl -MCPAN -e install Time::Piece
You don't have DBI installed for /usr/local/bin/perl, so install it.
/usr/local/bin/perl -MCPAN -e install DBI