Perl if not working? - perl

Here is my code:
#!/usr/bin/env perl
sub start
{
...
}
sub stop
{
...
}
if (defined $ARGV[0])
{
if ($ARGV[0]=='start') {start}
elsif ($ARGV[0]=='stop') {stop}
else {die "Unrecognized command: $ARGV[0]"}
}
Whatever I do though, it always executes &start. Am I doing something wrong?
I'm using Linux Mint 10 and Perl 5.10.1.

You're using numeric comparison to check string equality, which converts the arguments to numbers first before comparing them.
In this case, 'start' is not a number, so it gets converted to 0; the value in $ARGV[0] (which is expected to be a word here) is also converted, resulting in another 0 and a final condition of if (0 == 0), which is always true.
You want to use the eq string-wise comparison operator instead:
if ($ARGV[0] eq 'start') { start }
See the docs for more information on the different comparison operators.
Note that (as has been pointed out in the comments) including use warnings; at the top of your script would have caused perl to warn you about this from the start. Always including use warnings; and use strict; is generally best practice, as it helps catch these kinds of errors early.

The bug is that your program neglected to start with the standard boilerplate for Perl code.

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.

Perl using the special character &

I had a small question. I was reading some code and as my school didn't teach me anything useful about perl programming, I am here to ask you people. I see this line being used a lot in some perl programs:
$variable = &something();
I don't know what the & sign means here as I never say it in perl. And the something is a subroutine ( I am guessing). It usually says a name and it has arguments like a function too sometimes. Can someone tell me what & stands for here and what that something is all the time.
The variable takes in some sort of returned value and is then used to check some conditions, which makes me think it is a subroutine. But still why the &?
Thanks
Virtually every time you see & outside of \&foo and EXRP && EXPR, it's an error.
&foo(...) is the same as foo(...) except foo's prototype will be ignored.
sub foo(&#) { ... } # Cause foo to takes a BLOCK as its first arg
foo { ... } ...;
&foo(sub { ... }, ...); # Same thing.
Only subroutines (not operators) will be called by &foo(...).
sub print { ... }
print(...); # Calls the print builtin
&print(...); # Calls the print sub.
You'll probably never need to use this feature in your entire programming career. If you see it used, it's surely someone using & when they shouldn't.
&foo is similar to &foo(#_). The difference is that changes to #_ in foo affects the current sub's #_.
You'll probably never need to use this feature in your entire programming career. If you see it used, it's surely someone using & when they shouldn't or a foolish attempt at optimization. However, the following is pretty elegant:
sub log_info { unshift #_, 'info'; &log }
sub log_warn { unshift #_, 'warn'; &log }
sub log_error { unshift #_, 'error'; &log }
goto &foo is similar to &foo, except the current subroutine is removed from the call stack first. This will cause it to not show up in stack traces, for example.
You'll probably never need to use this feature in your entire programming career. If you see it used, it's surely a foolish attempt at optimization.
sub log_info { unshift #_, 'info'; goto &log; } # These are slower than
sub log_warn { unshift #_, 'warn'; goto &log; } # not using goto, but maybe
sub log_error { unshift #_, 'error'; goto &log; } # maybe log uses caller()?
$& contains what the last regex expression match matched. Before 5.20, using this causes every regex in your entire interpreter to become slower (if they have no captures), so don't use this.
print $& if /fo+/; # Bad before 5.20
print $MATCH if /fo+/; # Bad (Same thing. Requires "use English;")
print ${^MATCH} if /fo+/p; # Ok (Requires Perl 5.10)
print $1 if /(fo+)/; # Ok
defined &foo is a perfectly legitimate way of checking if a subroutine exists, but it's not something you'll likely ever need. There's also exists &foo is similar, but not as useful.
EXPR & EXPR is the bitwise AND operator. This is used when dealing with low-level systems that store multiple pieces of information in a single word.
system($cmd);
die "Can't execute command: $!\n" if $? == -1;
die "Child kill by ".($? & 0x7F)."\n" if $? & 0x7F;
die "Child exited with ".($? >> 8)."\n" if $? >> 8;
&{ EXPR }() (and &$ref()) is a subroutine call via a reference. This is a perfectly acceptable and somewhat common thing to do, though I prefer the $ref->() syntax. Example in next item.
\&foo takes a reference to subroutine foo. This is a perfectly acceptable and somewhat common thing to do.
my %dispatch = (
foo => \&foo,
bar => \&bar,
);
my $handler = $dispatch{$cmd} or die;
$handler->();
# Same: &{ $handler }();
# Same: &$handler();
EXPR && EXPR is the boolean AND operator. I'm sure you're familiar with this extremely common operator.
if (0 <= $x && $x <= 100) { ... }
In older versions of perl & was used to call subroutines. Now this is not necessary and \& is mostly used to take a reference to subroutine,
my $sub_ref = \&subroutine;
or to ignore function prototype (http://perldoc.perl.org/perlsub.html#Prototypes)
Other than for referencing subroutines & is bitwise and operator,
http://perldoc.perl.org/perlop.html#Bitwise-And

Perl script for creating two arrays

Input: A list of numbers on command line
Output: Two lists of numbers ,one with input numbers that are greater than zero and one with those that are less than zero (Ignoring zero valued numbers)
here is my code
#!/usr/bin/perl
$i++ = 0;
$j++ = 0;
while ($number = <>)
{
if($number<0)
$first[$i++]=$number;
else
$second[$j++]=$number;
}
print "The numbers with value less than zero are\n";
foreach $number (#first)
print $number;
print "The numbers with value greater than zero are\n"
foreach $number(#second)
print $number;
I am getting the following silly errors which i am not able to rectify.The errors are
divide.pl: 2: ++: not found
divide.pl: 3: ++: not found
divide.pl: 5: Syntax error: ")" unexpected
Can anybody help me out with rectifying these errors please? I am new to perl script
Curly braces on compound statements are not optional in Perl.
Your statements:
$i++=0;
$j++=0;
don't make sense; you probably just want to delete the "++".
You're missing a semicolon on one of your print statements.
Once you've got those problems fixed, you should add
use strict;
use warnings;
after the #! line. This will introduce more error messages; you'll need to fix those as well. For example, you'll need to declare your variables using my().
The code you present will hardly compile. Loops should have {} around the main block, arrays are better created with push (or unshift), you should use strict and warnings, and you can't do increments at the same time as assignments (e.g. $i++ = 0).
use v5.10;
use strict;
use warnings;
my (#first, #second);
while (<STDIN>) { # <STDIN> clearer than <> in this case
chomp;
if ($_ < 0) {
push #first, $_;
} elsif ($_ > 0) {
push #second, $_;
}
}
say "Numbers less than zero:";
say "#first";
say "Numbers greater than zero:";
say "#second";
I don't know what $i++ = 0 is supposed to mean, but change that to $i = 0 to initialize the variables.
Also, the first thing yuu should do in the while loop is call chomp($number) to remove spurious newlines - 5\n is not a number and treating it as one will confuse perl.
Once you've fixed that, post any new errors that show up - I don't see any other problems though.
How are you executing this perl script? Beyond the errors mentioned about the code itself. It looks like you are attempting to evaluate the code using dash instead of perl.
The errors you should be seeing if you were executing it with Perl would be like:
Can't modify postincrement (++) in scalar assignment at /tmp/foo.pl
line 2, near "0;"
But instead, your errors are more in line with what dash outputs:
$ dash /tmp/foo.pl
/tmp/foo.pl: 2: ++: not found
/tmp/foo.pl: 3: ++: not found
Once you've verified that you are running your perl script properly you can start working through the other problems people have mentioned your code. The easiest way to do this is to run it via perl divide.pl instead of whatever you are doing.

Perl while loop / reading file

I'm new to Perl and I have a problem when reading a file line by line. I started with a tutorial which suggested using a while loop. That worked fine, however I wanted to have an option to break out of the loop in case of an error. I know I can use the "last" keyword, but I don't like that very much, I would like to include it in the while loop's boolean expression so it is easier to see on what conditions it stops. So I did
$error=0;
while ( (!$error) && (<MYFILE>) ) {
print $_;
...
}
Unfortunately, this doesn't work because $_ seems to contain a "uninitialized value". For some reason, when I change (!$error) to (!0), it works again. I would understand that it was not working had I used || because of lazy evaluation, but with && in this case both sides need to be evaluated so I don't understand why it doesn't initialize the line variable.
The magical assignment to $_ only occurs if there is nothing else in the loop:
while (<MYFILE>) {
print $_;
...
}
If you want the error test too - which is not recommended - then you need to do the assignment:
my $error = 0;
while (!$error && ($_ = <MYFILE>)) {
print;
$error = 1 if m/quit/i;
}
Don't forget to add:
use warnings;
use strict;
The reason why the version with '!0' worked is probably because Perl optimizes and recognizes that '!0' is always true and removes it from the loop, leaving just the I/O operator, which then assigns to $_.
NB: it is far better to use idiomatic Perl and the last statement:
while (<MYFILE>) {
print;
last if m/quit/i;
}
First, as Jonathan points out you should always write languages idiomatically unless you have a very good reason and here you don't.
Your larger problem is misunderstanding the while loop. The automatic assignment of the result of the angle operator to $_ only occurs if it is the only thing in the while conditional test. If there are multiple items in the conditional test they are evaluated and then discarded (Programming Perl pp. 80-81 and I/O Operators at Perldoc).

Is 999...9 a real number in Perl?

sub is_integer {
defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
}
sub is_float {
defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/;
}
For the code mentioned above, if we give input as 999999999999999999999999999999999999999999, it is giving output as not real number.
Why it is behaving like that?
I forgot to mention one more thing:
If I am using this code for $x as the above value:
if($x > 0 || $x <= 0 ) {
print "Real";
}
Output is real.
How is this possible?
$ perl -e 'print 999999999999999999999999999999999999999999'
1e+42
i.e. Perl uses scientific representation for this number and that is why your regexp doesn't match.
Use the looks_like_number function from Scalar::Util (which is a core module).
use Scalar::Util qw( looks_like_number );
say "Number" if looks_like_number 999999999999999999999999999999999999999999;
# above prints "Number"
Just to add one more thing. As others have explained, the number you are working with is out of range for a Perl integer (unless you are on a 140 bit machine). Therefore, the variable will be stored as a floating point number. Regular expressions operate on strings. Therefore, the number is converted to its string representation before the regular expression operates on it.
Others have explained what is going on: out of the box, Perl can't handle numbers that large without using scientific notation.
If you need to work with large numbers, take a look at bignum or its components, such as Math::BigInt. For example:
use strict;
use warnings;
use Math::BigInt;
my $big_str = '900000000000000000000000000000000000000';
my $big_num = Math::BigInt->new($big_str);
$big_num ++;
print "Is integer: $big_num\n" if is_integer($big_num);
sub is_integer {
defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
}
Also, you may want to take a look at bignum in the Perl documentation.