Explanation of 'global symbol requires explicit package name' - perl

I've been learning Perl and whenever I write a non-trivial script I always get this error message. I always think I have a good understanding of it, but I suppose I don't. Here is a sloppy markov chain example (not tested) with the errors below.
The
#!/usr/bin/perl -w
use strict;
sub croak { die "$0: #_: $!\n"; }
sub output {
my %chains = shift;
my #keys = keys %chains;
my $index = rand($keys);
my $key = $keys[$index];
my $out_buf = $key;
for (my $i = 0; $i < 100; ++$i) {
my $aref = $chains{$key};
my $word = #$aref[rand($aref)];
$out_buf .= " $word";
$key =~ s/.+ //;
$key .= " $word";
}
print $out_buf, "\n";
}
sub get_chains {
my %chains;
my #prefixes
while (my $line = <FILE>) {
my #words = split " ", $line;
foreach my $word (#words) {
if ($prefixes == 2) {
my $key = join " ", #prefixes;
my $arr_ref = $chains{$key};
push(#$arr_ref, $word);
shift #prefixes;
}
push(#prefixes, $word);
}
}
return %chains;
}
sub load_book {
my $path_name = shift #ARGV;
open(FILE, $path_name) || croak "File not found.\n";
}
load_book;
my %chains = get_chains;
output %chains;
----ERRORS----
"my" variable $line masks earlier declaration in same statement at markov.pl line 33.
"my" variable $path_name masks earlier declaration in same scope at markov.pl line 55.
Global symbol "$keys" requires explicit package name at markov.pl line 12.
syntax error at markov.pl line 32, near ") {"
Global symbol "$prefixes" requires explicit package name at markov.pl line 36.
Global symbol "%chains" requires explicit package name at markov.pl line 48.
syntax error at markov.pl line 49, near "}"
syntax error at markov.pl line 56, near "}"
Execution of markov.pl aborted due to compilation errors.
What mistake(s) am I making?

There are three syntax errors in your script:
Global symbol "$keys" requires explicit package name at markov.pl line 12.
You didn't declare $keys, and because of "use strict", that is a fatal error.
You probably meant:
my $index = rand(#keys);
The second error:
Global symbol "$prefixes" requires explicit package name at markov.pl line 36.
is the same thing: you meant:
if (#prefixes == 2) {
Finally, in line 30, you're missing a semicolon after:
my #prefixes
This confuses the parser, and causes all the other errors and warnings.
You may want to read the perldata documentation if you're unclear about the use of sigils ($, #, %).

Related

SOLVED: Hash content access is inconsistent with different perl version

I came across an interesting problem with following piece of code in perl 5.22.1 and perl 5.30.0
use strict;
use warnings;
use feature 'say';
#use Data::Dumper;
my %hash;
my %seen;
my #header = split ',', <DATA>;
chomp #header;
while(<DATA>) {
next if /^\s*$/;
chomp;
my %data;
#data{#header} = split ',';
push #{$hash{person}}, \%data;
push #{$hash{Position}{$data{Position}}}, "$data{First} $data{Last}";
if( ! $seen{$data{Position}} ) {
$seen{$data{Position}} = 1;
push #{$hash{Role}}, $data{Position};
}
}
#say Dumper($hash{Position});
my $count = 0;
for my $person ( #{$hash{person}} ) {
say "Person: $count";
say "Role: $person->{Position}";
}
say "---- Groups ----\n";
while( my($p,$m) = each %{$hash{Position}} ) {
say "-> $p";
my $members = join(',',#{$m});
say "-> Members: $members\n";
}
say "---- Roles ----";
say '-> ' . join(', ',#{$hash{Role}});
__DATA__
First,Last,Position
John,Doe,Developer
Mary,Fox,Manager
Anna,Gulaby,Developer
If the code run as it is -- everything works fine
Now it is sufficient to add $count++ increment as bellow and code produces errors
my $count = 0;
for my $person ( #{$hash{person}} ) {
$count++;
say "Person: $count";
say "Role: $person->{Position}";
}
Errors:
Error(s), warning(s):
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 24, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 3.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 3.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 4.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in join or string at source_file.pl line 48, <DATA> line 4.
This problem does not manifest itself in perl 5.30.0 (Windows 10, Strawberry Perl) or Perl v5.24.2.
Note: the problem manifests itself not only with $count++ but with any other access to content of the hash next to say "Person: $count"; -- post# 60653651
I would like to hear comments on this situation, what is the cause?
CAUSE: input data have eol in DOS form \r\n and when data processed in Linux chomp removes only \n leaving \r as part of the field name (used as hash key). Thanks goes to Shawn for pointing out the source of the issue.
SOLUTION: universal fix was implemented in form of snip_eol($arg) subroutine
use strict;
use warnings;
use feature 'say';
my $debug = 0;
say "
Perl: $^V
OS: $^O
-------------------
" if $debug;
my %hash;
my %seen;
my #header = split ',', <DATA>;
$header[2] = snip_eol($header[2]); # problem fix
while(<DATA>) {
next if /^\s*$/;
my $line = snip_eol($_); # problem fix
my %data;
#data{#header} = split ',',$line;
push #{$hash{person}}, \%data;
push #{$hash{Position}{$data{Position}}}, "$data{First} $data{Last}";
if( ! $seen{$data{Position}} ) {
$seen{$data{Position}} = 1;
push #{$hash{Role}}, $data{Position};
}
}
#say Dumper($hash{Position});
my $count = 0;
for my $person ( #{$hash{person}} ) {
$count++;
say "-> Name: $person->{First} $person->{Last}";
say "-> Role: $person->{Position}\n";
}
say "---- Groups ----\n";
while( my($p,$m) = each %{$hash{Position}} ) {
say "-> $p";
my $members = join(',',#{$m});
say "-> Members: $members\n";
}
say "---- Roles ----";
say '-> ' . join(', ',#{$hash{Role}});
sub snip_eol {
my $data = shift; # problem fix
#map{ say "$_ => " . ord } split '', $data if $debug;
$data =~ s/\r// if $^O eq 'linux';
chomp $data;
#map{ say "$_ => " . ord } split '', $data if $debug;
return $data;
}
__DATA__
First,Last,Position
John,Doe,Developer
Mary,Fox,Manager
Anna,Gulaby,Developer
I can replicate this behavior by (On linux) first converting the source file to have Windows-style \r\n line endings and then trying to run it. I thus suspect that in your testing of various versions you're using Windows sometimes, and a Linux/Unix other times, and not converting the file's line endings appropriately.
#chomp only removes a newline character (Well, the current value of $/ to be pedantic), so when used on a string with a Windows style line ending in it, it leaves the carriage return. The hash key is not "Position", it's "Position\r", which is not what the rest of your code uses.

perl script returns error global symbol requires explicit package

I am trying to write a perl script having a menu in which user selects one in list (1-3) and then asks the user to enter a string (depending on menu selected) which should be read as input and printed in console. However when executing script, I am finding this error. What could be wrong here?
~] # perl sample.pl
Global symbol "$user" requires explicit package name at ./sample.pl line 26.
Global symbol "$user" requires explicit package name at ./sample.pl line 27.
Global symbol "$user" requires explicit package name at ./sample.pl line 28.
Global symbol "$process" requires explicit package name at ./sample.pl line 37.
Global symbol "$process" requires explicit package name at ./sample.pl line 38.
Global symbol "$process" requires explicit package name at ./sample.pl line 39.
Missing right curly or square bracket at ./sample.pl line 52, at end of line
syntax error at ./sample.pl line 52, at EOF
Execution of ./sample.pl aborted due to compilation errors.
#!/usr/bin/perl
use strict;
use warnings;
use Switch;
my $input = '';
while ($input ne '3')
{
clear_screen();
print "1. user\n".
"2. process\n".
"3. exit\n";
print "Enter choice: ";
$input = <STDIN>;
chomp($input);
{
case '1'
{
print "Enter user";
$user = <STDIN>;
chomp ($user);
print "User is $user\n";
}
case '2'
{
print "Enter process:";
$process = <STDIN>;
chomp ($process);
print "Process is $process\n";
}
}
If you use perltidy to format your code, you can easily see that there's an unmatched bracket:
#!/usr/bin/perl
use warnings;
my $input='';
while ( $input ne '3' ) {
clear_screen();
print "1. user\n" . "2. process\n" . "3. exit\n";
print "Enter choice: ";
$input=<STDIN>;
chomp($input);
{ ## <-- this open brace is probably the culprit of the error
if ( $input eq '1' ) {
print "Enter user";
$user=<STDIN>;
chomp($user);
print "User is $user\n";
}
else {
print "Enter process:";
$process=<STDIN>;
chomp($process);
print "Process is $process\n";
}
}
Code formatting isn't just about making code look nice; it also makes it easier to track down errors and for others to understand. You should also use strict; on all your scripts to ensure that potential programming errors get caught before they cause problems in your code.

Use of uninitialized value but variables declared

use strict;
use warnings;
my $last_variable2= 'abc';
print "last var2 $last_variable2\n";
my #grouped;
while (<DATA>) {
my ($variable1,
$variable2,
$other_data) = split ',',$_,3;
if($variable2 ne 'abc'){
if( $variable2 ne $last_variable2){
print "\n\n";
print "'$variable2' doesn't equal '$last_variable2'\n";
my %HoA;
&process_data(#grouped_series);
#grouped = ();
}
}else{
print "Skipped this because it's the first\n";
}
push #grouped_series, $_;
$last_variable2 = $variable2;
}
When I run this code, I keep getting
Use of uninitialized value $last_variable2 in string ne at 1_1_correspondencer.pl line 32, <DATA> line 3.
Use of uninitialized value $variable2 in string ne at 1_1_correspondencer.pl line 33, <DATA> line 3.
Use of uninitialized value $last_variable2 in concatenation (.) or string at 1_1_correspondencer.pl line 36, <DATA> line 6.
But, I initialized both variables. Sorry, this is a naive question--I only just started using strict and warnings
When parsing your DATA, you don't verify that each of these variables is defined:
my ($variable1,
$variable2,
$other_data) = split ',',$_,3;
If there are no commas on a row, then $variable2 would be undefined which is later assigned to $last_variable2. Maybe add some data verification to take into account that case?
if (! defined $variable2) {
warn "missing variable2 definition: $_\n";
}
Without seeing your actual data, we can't really advise you more.

Printing a perl script within another perl script?

Hi I am new to stackoverflow. I've tried looking a way to print another perl script within a different perl script and the only advice I came across is escaping the variables using a backslash...but I tried this and it does not work.
My goal is to write a perl script to make a bunch of new perl scripts but as it is it won't allow me to use variable/arrays/etc in a print "". Is there a way around this? Thanks in advance!
Here is my preliminary script:
#!/usr/bin/perl
use warnings;
use strict;
my $idfile = $ARGV[0];
open (IDFILE,'<',$idfile)
or die "Could not open $idfile \n";
my $outfile_name;
my $outfile = $outfile_name."pl";
open (OUTFILE, '>', $outfile)
or die "Could not open $outfile \n";
while (my $line = <IDFILE>) {
chomp ($line);
if ($line =~ /(T4-GC_[0-9]+)/) {
my $outfile_name = "Pull_".$line;
my $script = "
#!/usr/bin/perl
use warnings;
use strict;
use Bio::SearchIO;
use Bio::SeqIO;
my #ARGV = glob("*.fa");
foreach my $fil (#ARGV) {
my $seqio = Bio::SeqIO->new(-format => 'fasta', -file => $fil);
while (my $seqobj = $seqio->next_seq) {
my $seqid = $seqobj->display_id;
$fil =~ /([A-Z]+[0-9]+)/;
my $phage_name = $1;
my $id = $seqid."|".$phage_name;
my $nuc = $seqobj->seq();
if ($seqid =~ /**$line**/) {
print ">$id\n$nuc\n";
}
}
}"
print OUTFILE $script;
}
}
And this is the error I get back:
String found where operator expected at make_perl_pull_genes_files.pl line 33, near "my $id = $seqid.""
(Might be a runaway multi-line "" string starting on line 25)
(Missing semicolon on previous line?)
Backslash found where operator expected at make_perl_pull_genes_files.pl line 36, near "$id\"
(Might be a runaway multi-line "" string starting on line 33)
(Missing operator before \?)
Backslash found where operator expected at make_perl_pull_genes_files.pl line 36, near "$nuc\"
(Missing operator before \?)
String found where operator expected at make_perl_pull_genes_files.pl line 39, near "}""
(Might be a runaway multi-line "" string starting on line 36)
(Missing semicolon on previous line?)
syntax error at make_perl_pull_genes_files.pl line 25, near "*."
(Might be a runaway multi-line "" string starting on line 18)
Global symbol "$id" requires explicit package name at make_perl_pull_genes_files.pl line 36.
Global symbol "$nuc" requires explicit package name at make_perl_pull_genes_files.pl line 36.
Execution of make_perl_pull_genes_files.pl aborted due to compilation errors.
Use a HERE document with single quotes around the leading delimiter.
print <<'EOT';
#!/usr/bin/perl
use warnings;
use strict;
use Bio::SearchIO;
use Bio::SeqIO;
my #ARGV = glob("*.fa");
foreach my $fil (#ARGV) {
my $seqio = Bio::SeqIO->new(-format => 'fasta', -file => $fil);
while (my $seqobj = $seqio->next_seq) {
my $seqid = $seqobj->display_id;
$fil =~ /([A-Z]+[0-9]+)/;
my $phage_name = $1;
my $id = $seqid."|".$phage_name;
my $nuc = $seqobj->seq();
if ($seqid =~ /**$line**/) {
print ">$id\n$nuc\n";
}
}
}
EOT
Note that the trailing delimiter must be cuddled by newlines: \nTRAILING\n in your source. Don't attempt to indent it, for instance. Another place you can stuff text like this, within your source file, is beyond a __DATA__ line. You would then read it back through <DATA>.

Perl explicit package name errors in while loop and require troubles

Running this code
parsesendnotes.pl
#!/usr/bin/perl
use strict;
use warnings;
use Device::SerialPort;
use Time::HiRes qw(usleep); # For sleep in ms
if ($#ARGV + 1 != 2) {
print "Usage: $0 port filename\n";
print "Example: $0 /dev/ttyASM0 money.txt\n";
exit 1;
}
my $file = $ARGV[0];
my $dev = $ARGV[1];
if (!-e $file || !-e $dev) {
print "File or brain not found.\n";
exit 1;
}
my $arduino = DeviceSerialPort->new($dev);
$arduino->baudrate(9600);
$arduino->databits(8);
$arduino->parity("none");
$arduino->stopbits(1);
require "frequencies.pl";
open NOTES, "$file";
print $frequencies{"LA3"};
while (<NOTES>) {
chomp; # No newline
s/#.*//; # No comments
s/^\s+//; # No leading white
s/\s+$//; # No trailing white
next unless length;
if ($_ =~ m/^TEMPO/) {
my $tempo = split(/\s+/, $_, -1);
print "Tempo is $tempo.";
} else {
my #tone = split(/\s+/, $_);
}
my $note = $frequencies{$tone[0]};
my $duration = $tone[1]*$tempo;
print "Playing $tone[0] (\#$note Hz) for $tone[1] units ($duration ms).";
while ($note > 255) {
$arduino->write(chr(255));
$note -= 255;
}
$arduino->write(chr($note));
$arduino->write(";");
usleep($duration);
}
frequencies.pl
my %frequencies = (
"PAUSE" => 0,
"B0" => 31,
"DO1" => 33,
"DOD1" => 35,
...
);
I obtain these errors
Global symbol "%frequencies" requires explicit package name at ./parsensendnotes2.pl line 30.
Global symbol "%frequencies" requires explicit package name at ./parsensendnotes2.pl line 44.
Global symbol "#tone" requires explicit package name at ./parsensendnotes2.pl line 44.
Global symbol "#tone" requires explicit package name at ./parsensendnotes2.pl line 45.
Global symbol "$tempo" requires explicit package name at ./parsensendnotes2.pl line 45.
Global symbol "#tone" requires explicit package name at ./parsensendnotes2.pl line 46.
Global symbol "#tone" requires explicit package name at ./parsensendnotes2.pl line 46.
Execution of ./parsensendnotes2.pl aborted due to compilation errors.
What am I doing wrong?
name %frequencies is localized in file frequencies.pl: my lasts until end of block, or end of file.
A better way would be to remove my and do like this:
my %frequencies;
eval { %frequencies = do "frequencies.pl"; }
# must check $! and $# here -- see perldoc -f do`
However, an even better way is to use YAML instead:
freq.yml
---
"PAUSE": 0
"B0": 31
"DO1": 33
"DOD1": 35
And then
use YAML qw(LoadFile);
# ...
my $data = LoadFile("freq.yml");
%frequencies = %$data;
As for #tone, $tempo & co, again, my variable scope is limited to {} block. You should do something like
my $x;
if (...) { $x = ... };
to make $x accessible outside if.
my %frequencies from frequencies.pl is not declared inside parsesendnotes.pl.
You need our %frequencies in your main script. And of course the same for the other variables.
Some documentation:
perldoc -f my
perldoc -f our