views:

129

answers:

5

I've just noticed a strange behavior of perl5 (5.10.0) when I passed 0 as the command-line argument to a script, which assigns it to a variable. The problem I encountered is that if I give the variable a default value in my script which is greater than 0, say 1, then I can pass any value except 0 to override the default value 1.

Following is the code of 'test.pl' I used:

#!/usr/bin/perl -w  
my $x = shift || 1;  
print "x is $x\n";  

Following are the commands and ouputs when I tested it:

$ ./test.pl 2  
x is 2  
$ ./test.pl 0  
x is 1  

I'd appreciate if anyone can shed light on this. Thanks. wwl

+7  A: 

The expression shift || 1 chooses the rhs iff the lhs evaluates to "false". Since you are passing 0, which evaluates to "false", $x ends up with the value 1.

Marcelo Cantos
+12  A: 

If you want $x to have the value of "1" in case no argument is provided, use this:

my $x = shift // 1;  

From perldoc perlop:

"//" is exactly the same as "||", except that it tests the left hand side's definedness instead of its truth.

Note: the defined-or operator is available starting from 5.10 (released on December 18th, 2007)

eugene y
Don't forget `use 5.10.0;`
Greg Bacon
I have a feeling this was introduced in quite a recent version of Perl, can you say which one? Then I'll +1.
j_random_hacker
@gbacon: Thanks. Since quite a few of us are still on earlier versions, could you mention this in your answer please eugene y? Thanks.
j_random_hacker
Thank eveyone who answered. I didn't expect get an answer so quickly. Thanks, eugene, I guess you are the first one to answer.
Wayne
A: 

In this line my $x = shift || 1; the shift failed the test and therefore the conditional logical OR || was executed and assigned 1 to it... as per the page on shift the value was 0 which implies empty array....

tommieb75
+3  A: 

use defined-or operator, because string "0" is defined, but not evaluated as true.

#!/usr/bin/perl -w  
my $x = shift // 1;  
print "x is $x\n";  
Alexandr Ciornii
Yes, but as gbacon mentions in a comment elsewhere, this does require Perl 5.10 or later.
j_random_hacker
j_random_hacker: Wayne is using 5.10.0, which is 2.5 years old.
Alexandr Ciornii
Good point Alexandr! :)
j_random_hacker
+6  A: 

The best approach is the one in eugene's and Alexandr's answers, but if you're stuck with an older perl, use

my $x = shift;
$x = 1 unless defined $x;

Because you have a single optional argument, you could examine @ARGV in scalar context to check how many command-line arguments are present. If it's there, use it, or otherwise fall back on the default:

my $x = @ARGV ? shift : 1;
Greg Bacon