Perl compilation problem that Perl::Critic does not see - perl

I have this if statement that does not pass compilation:
my $string_var;
if ( $string_var eq "string_value1" || $string_var eq "string_value2" ) &&
(defined $ENV{VAR_NAME}) {
die { "error_message" => "error_message" }
}
Neither I nor Perl::Critic see a problem. But Perl says:
syntax error at /opt/app_protect/bin/../lib/perl/F5/BdCfg/Bundle.pm line 178, near ") &&"
syntax error at /opt/app_protect/bin/../lib/perl/F5/BdCfg/Bundle.pm line 181, near "}"
Can anyone help?
It's CentOS 7.6.1810 with Perl v5.16.3

From perlsyn:
The following compound statements may be used to control flow: ...if (EXPR) BLOCK
What you provide here is not
if (EXPR) BLOCK
but instead
if (EXPR1) && (EXPR2) BLOCK
This needs to be enclosed in parentheses in order to be a valid syntax, i.e.
if ((EXPR1) && (EXPR2)) BLOCK

Related

Perl else error

Hello I am new to programming in perl I am trying to make a number adder (math) but it gives me 1 error here's my code:
sub main {
print("First: ");
$num1 = <STDIN>;
print("Second: ");
$num2 = <STDIN>;
$answer = $num1 + $num2;
print("$answer")
} else {
print("You have entered invalid arguments.")
}
main;
now obviously its not done but I get an error on ONLY else here is the error:
C:\Users\aries\Desktop>"Second perl.pl"
syntax error at C:\Users\aries\Desktop\Second perl.pl line 9, near "} else"
Execution of C:\Users\aries\Desktop\Second perl.pl aborted due to compilation errors.
please help (also I tried googling stuff still error)
Since you're new to Perl, I recommend you add strict and warnings at the top of your scripts. This will help identify common problems and potentially dangerous code.
The main problem with your code is that you've appended the else statement to your subroutine. Here is an example of your code as I think you intended it to be:
use strict;
use warnings;
use Scalar::Util qw(looks_like_number);
sub main {
print 'First :';
my $num1 = <STDIN>;
print 'Second: ';
my $num2 = <STDIN>;
if( looks_like_number($num1) && looks_like_number($num2) ) {
my $answer = $num1 + $num2;
print "$answer\n";
}
else {
die 'You have entered invalid arguments.';
}
}
main();
There are a few things I should note here about the differences between Perl and Python that I think will help you understand Perl better.
Unlike Python, Perl doesn't care about white space. It uses curly braces and semi-colons to indicate the end of blocks and statements and will happily ignore any white space that isn't in quotes.
The else statement appended to the subroutine won't work because Perl isn't designed to evaluate code blocks that way. A subroutine is simply a named code block that can be called at any other point in the script. Any error handling will need to be done inside of the subroutine rather than to it.
Perl is very context-sensitive and doesn't make a solid distinction between strings and integers in variables. If you write $var_a = 1, Perl will read it as an integer. $var_b = '1', it will read it as a string. But, you can still add them together: $var_c = ($var_a + $var_b), and Perl will make $var_c = 2.
This is another reason the else statement would not work as you've written it. Python would throw an error if you try to add non-integers, but Perl will just figure out how to combine them, and give you the result. If you try to add a letter and a number, Perl still won't fail, but it will warn you if you put "use warnings;" at the top of your script.
In the example, and as Dada mentioned, you can use the looks_like_number() method from the Scalar::Utils module to evaluate the variables as you had intended.
Apart from the syntax, if/else statements work the same way in Perl as in Python. The else-if is slightly different as is has an extra s:
if (condition) {
...
}
elsif (other condition) {
...
}
else {
...
}
In Perl, it's good practice to assign lexical scope to variables using the my function. Since Perl is so context-sensitive, this can help prevent unexpected behavior when moving between different scopes.
Single- and double-quotes have different uses in Perl. Single-quotes are read literally and double-quotes are interpolated, so if you want to combine variables and text together, you can skip concatenating the strings and just do: print "Got variable: $var\n";
Lastly, note that I added parentheses after the main subroutine call. This is another best practice to make it clearer that you are calling a subroutine as opposed to it being a bare word or a bad variable name.

why the syntax `&name arg1 arg2 ...` can't be used to call a Perl subroutine?

for a Perl subroutine, if passing 0 argument, I can use 4 forms to call it. But if passing 1 or more arguments, there is one form that I can't use, please see below:
sub name
{
print "hello\n";
}
# 4 forms to call
name;
&name;
name();
&name();
sub aname
{
print "#_\n";
}
aname "arg1", "arg2";
#&aname "arg1", "arg2"; # syntax error
aname("arg1", "arg2");
&aname("arg1", "arg2");
The error output is
String found where operator expected at tmp1.pl line 16, near "&aname "arg1""
(Missing operator before "arg1"?)
syntax error at tmp1.pl line 16, near "&aname "arg1""
Execution of tmp1.pl aborted due to compilation errors.
Can someone explain the error output from the compiler's point of view? I don't understand why it complains about missing operator.
Thanks
It's documented in perlsub:
To call subroutines:
NAME(LIST); # & is optional with parentheses.
NAME LIST; # Parentheses optional if predeclared/imported.
&NAME(LIST); # Circumvent prototypes.
&NAME; # Makes current #_ visible to called subroutine.
With &NAME "arg", perl sees &NAME() "ARG", so it thinks there's an operator missing between the sub call and "ARG".
In Perl 5, you don't need the & in most cases.

Definition of empty {} after If() statement in eval{} statement

I am currently attempting to document a Perl script in preparation for converting it to .NET. I have no prior experience in Perl before now, however I was managing to get through it with a lot of Google-fu. I have run into a single line of code that has stopped me as I am unsure of what it does. I've been able to figure out most of it, but I'm missing a piece and I don't know if it's really that important. Here is the line of code:
eval { if(defined $timeEnd && defined $timeStart){}; 1 } or next;
I know that defined is checking the variables $timeEnd and $timeStart to see if they are null/nothing/undef. I also believe that the eval block is being used as a Try/Catch block to trap any exceptions. The line of code is in a foreach loop so I believe the next keyword will continue on with the next iteration of the foreach loop.
The part I'm having difficulty deciphering is the {};1 bit. My understanding is that the ; is a statement separator in Perl and since it's not escaped with a backslash, I have no idea what it is doing there. I also don't know what the {} means. I presume it has something to do with an array, but it would be an empty array and I don't know if it means something special when it is directly after an if() block. Lastly, I no idea what a single integer of 1 means and is doing there at the end of an eval block.
If someone could break that line of code down into individual parts and their definitions, I would greatly appreciate it.
Bonus: If you can give me a .NET conversion, and how each Perl bit relates to it, I will most certainly give you my internet respects. Here's how I would convert it to VB.NET with what I know now:
For each element in xmlList 'This isn't in the Perl code I posted, but it's the `foreach` loop that the code resides in.
Try
If Not IsNothing(timeEnd) AND Not IsNothing(timeStart) then
End If
Catch ex as Exception
Continue For
End Try
Next
Ignoring elsif and else clasuses, the syntax of an if statement is the following:
if (EXPR) BLOCK
The block is executed if the EXPR evaluates to something true. A block consists of a list of statements in curly braces. The {} in your code is the block of the if statement.
It's perfectly valid for blocks to be empty (to contain a list of zero statements). For example,
while (s/\s//) { }
is an inefficient way of doing
s/\s//g;
The thing is, the condition in the following has no side-effects, so it's quite useless:
if(defined $timeEnd && defined $timeStart){}
It can't even throw an exception![1] So
eval { if(defined $timeEnd && defined $timeStart){}; 1 } or next;
is equivalent to
eval { 1 } or next;
which is equivalent to[2]
1 or next;
which is equivalent to
# Nothing to see here...
Technically, it can if the variables are magical.
$ perl -MTie::Scalar -e'
our #ISA = "Tie::StdScalar";
tie(my $x, __PACKAGE__);
sub FETCH { die }
defined($x)
'
Died at -e line 4.
I doubt the intent is to check for this.
Technically, it also clears $#.
eval{} returns result of last expresion (1 in your example) or undef if there was an exception. You can write same code as,
my $ok = eval {
if (defined $timeEnd && defined $timeStart){};
1
};
$ok or next;
From perldoc -f eval
.. the value returned is the value of the last expression evaluated inside the mini-program; a return statement may be also used, just as with subroutines.
If there is a syntax error or runtime error, or a die statement is executed, eval returns undef in scalar context or an empty list in list context, and $# is set to the error message

Deciphering this syntax error

I cant seem to understand the reason for these syntax errors. The following is part of my code. I have strict and warnings implemented.
my $res = $s->scrape(URI->new($urlToScrape));
#warn Dump $res;
print "Show :".$res->{showtitle}[0];
my #sct;
if ( defined {season}[0] ) {
print $res->{season}[0];
#sct=split(' ', $res->{season}[0]);
} else {
my #spaa=split( {showtitle}[0], {fulltitle}[0] );
print "Couldnt find season num at proper position\n";
print $spaa[0]."\n";
print $spaa[1]."\n";
exit;
}
The error I get is:
$ ./htmlscrape.pl
"my" variable #spaa masks earlier declaration in same scope at ./htmlscrape.pl line 43.
"my" variable #spaa masks earlier declaration in same scope at ./htmlscrape.pl line 44.
syntax error at ./htmlscrape.pl line 37, near "}["
syntax error at ./htmlscrape.pl line 40, near "}"
syntax error at ./htmlscrape.pl line 46, near "}"
Execution of ./htmlscrape.pl aborted due to compilation errors.
There's syntax error in your code. Change:
if ( defined {season}[0] )
to
if ( defined $res->{season}[0] )
and
my #spaa=split( {showtitle}[0], {fulltitle}[0] );
to
my #spaa=split( $res->{showtitle}[0], $res->{fulltitle}[0] );
Also you are getting the warning
"my" variable #spaa masks earlier declaration in same scope at ./htmlscrape.pl line 43.
That means you have declared two arrays with the same name #spaa in same scope. You'll probably find Coping with Scoping by Dominus worth reading. Pay particular attention to the section called "Lexical Variables".

New to perl; getting some errors I'm not sure about

I can't seem to figure out why I'm getting this error when trying to run my .pl script.
Here is the script:
# mini script for creating diff files in a single directory
# directory of patch files
$patchDir = "c:\oc\Patch Files";
if ($#ARGV != 1 && $#ARGV != 2)
{
print "Usage: diff <file name> [-s]\n";
print "Example: \n";
print " |Diff relative to Index (staged)| : diff MOM00123456_1.patch \n";
print " |Diff Staged| : diff MOM00123456_1.patch -s \n";
exit;
}
$fileName = $ARGV[0];
if ($#ARGV == 2)
$stagedArg = $ARGV[1];
if ($stagedArg)
if ($stagedArg == "-s" || $stagedArg == "-S")
system("git diff --staged --full-index > $fileName $patchDir");
else
{
print "Unknown argument: $stagedArg\n";
exit;
}
else
system("git diff --full-index > $fileName $patchDir");
Test:
diff.pl test.patch -s
Output:
Scalar found where operator expected at C:\utils\diff.pl line 18, near
")
$stagedArg"
(Missing operator before $stagedArg?) syntax error at C:\utils\diff.pl line 18, near ")
$stagedArg " syntax error at C:\utils\diff.pl line 21, near ")
if" Execution of C:\utils\diff.pl aborted due to compilation errors.
Execution of C:\utils\diff.pl aborted due to compilation errors.
Can someone shed some light?
Perl if syntax is:
if (condition) {
statements;
}
You can't omit the curly braces.
You might find use diagnostics; useful. Given a simple test script:
use strict;
use warnings;
use diagnostics;
if (1)
print 1;
We get:
syntax error at - line 5, near ")
print"
Execution of - aborted due to compilation errors (#1)
(F) Probably means you had a syntax error. Common reasons include:
A keyword is misspelled.
A semicolon is missing.
A comma is missing.
An opening or closing parenthesis is missing.
An opening or closing brace is missing.
A closing quote is missing.
Often there will be another error message associated with the syntax
error giving more information. (Sometimes it helps to turn on -w.)
The error message itself often tells you where it was in the line when
it decided to give up. Sometimes the actual error is several tokens
before this, because Perl is good at understanding random input.
Occasionally the line number may be misleading, and once in a blue moon
the only way to figure out what's triggering the error is to call
perl -c repeatedly, chopping away half the program each time to see
if the error went away. Sort of the cybernetic version of 20 questions.
Uncaught exception from user code:
syntax error at - line 5, near ")
print"
Execution of - aborted due to compilation errors.