Sakura
Sakura

Reputation: 969

How to avoid errors with perl command line parameters and use strict

Why is it that my code is not working after I added use strict; use warnings;? Is there a way to make it work?

Previously, the working code is:

#!/usr/bin/perl -s
print "x: $x\n";
print "y: $y\n";

The command that I ran is perl -s test.pl -x="hello" -y="world". The output is:

x: hello
y: world

However, after I added use strict; use warnings;, I got the following errors:

Variable "$x" is not imported at test.pl line 4.
Variable "$y" is not imported at test.pl line 5.
Global symbol "$x" requires explicit package name at test.pl line 4.
Global symbol "$y" requires explicit package name at test.pl line 5.
Execution of test.pl aborted due to compilation errors.

I know I need to declare my $x and my $y to fix the 3rd and 4th error. But what does the first 2 errors mean and how do I overcome it?

Upvotes: 8

Views: 8051

Answers (3)

ruakh
ruakh

Reputation: 183251

Actually, declaring these variables as lexical (my) variables will not help, because it's too "late": the -s switch will already have set them. It sets the global (package) variables (in your case, $main::x and $main::y, or — as a special shorthand — $::x and $::y). If you don't want to have to refer to them using their package-qualified names, then you can use an our declaration to indicate that the bare names $x and $y refer to the $x and $y in the current package:

our ($x, $y);
print "x: $x\n"; 
print "y: $y\n";

(Hat-tip to derobert for pointing out that you can use our for this.)

Alternatively, you can copy the global variables into identically-named lexical variables:

my ($x, $y) = ($::x, $::y);
print "x: $x\n";
print "y: $y\n";

This will take care of both sets of diagnostics.

Upvotes: 9

TLP
TLP

Reputation: 67900

You are using a a rudimentary switch parser perl -s, which uses global variables. To make it work with use strict you need to refer to the globals: $main::x as ruakh pointed out.

But even so, lexical variables (declared with my) are preferable in just about all cases. Just do:

use strict;
use warnings;

my ($x, $y) = @ARGV;
print "x: $x\n";
print "y: $y\n";

And use with:

perl test.pl hello world

For a more detailed and switch like handling, check out the Getopt::Long module.

Upvotes: 4

DVK
DVK

Reputation: 129383

To understand what ANY Perl error/warning means, you can refer to perldiag.

Specifically, for "is not imported", it says:

Variable "%s" is not imported%s

(W misc) With "use strict" in effect, you referred to a global variable that you apparently thought was imported from another module, because something else of the same name (usually a subroutine) is exported by that module. It usually means you put the wrong funny character on the front of your variable.

Basically, Perl made 2 distinct guesses about your un-declared identifyer $x - it was either

  1. a package-scoped global that is prohibited from being used under strict ("Global symbol "$x" requires explicit package")

  2. or it was an attempt to use another package's variable that ought to have been imported but wasn't ("Variable "$x" is not imported").

Perl can not tell WHICH of the two theories are correct, so spat out both possibilities. The latter error (Global symbol "$x" requires explicit package name) was the correct one in this case - it WAS a global variable in your original pre-strict code.

Upvotes: 2

Related Questions