use strict;
use warnings;
sub XX { 30 };
my $rnd = 3;
my $z = -XX * $rnd;
Give error: Can't use string ("3") as a symbol ref while "strict refs" in use
This does not help:
my $z = -XX * ($rnd);
I get next error:
Scalar found where operator expected at game4.pl line 7, near "* ($rnd"
(Missing operator before $rnd?)
syntax error at game4.pl line 7, near "* ($rnd"
Execution of game4.pl aborted due to compilation errors.
How to force EXPR instead of GLOB dereference?
A few options.
Explicitly tell Perl that you're not passing parameters to XX.
my $z = -XX() * $rnd;
Use the old-style calling conventions for subroutines (I really don't recommend this one).
my $z = -&XX * $rnd;
Define the subroutine as not taking parameters.
sub XX() { 30 };
But the best solution is to use the built-in constant pragma.
use constant XX => 30;
Related
Hopefully you can help a scientist to decipher whats wrong with the code I'm trying to run to clean up some NGS results. The Perl file itself comes from https://github.com/mtokuyama/ERVmap, though I am posting the code below for reference. The other Perl files in the package work just fine and, while I have built a passing ability to use the linux terminal, Perl is a little beyond me.
The linux terminal I'm using is currently running: Ubuntu 16.04.6 LTS
This is the Perl code I'm trying to run using the following command line on linux as instructed by their GitHub page:
perl clean_htseq.pl ./ c c2 __
#!/usr/bin/env perl
#$Id: run_clean_htseq.pl,v 1.2 2015/03/02 17:24:35 yk336 Exp $
#
# create pbs file
#
use warnings;
use strict;
use File::Basename;
use POSIX;
my $dir = shift;
my $e1 = shift;
my $e2 = shift;
my $stop = shift;
die "$e1 eq $e2" if ($e1 eq $e2);
my $find = "find $dir -name \"*${e1}\"";
my $out = `$find`;
my #files = split(/\n/, $out);
for my $f (#files) {
my $o = $f;
$o =~ s/${e1}$/$e2/;
my $cmd = "./clean_htseq.pl $stop $f > $o";
print "$cmd\n";
system($cmd);
}
The first error that I had was that the _clean_htseq.pl_ wasn't found (line 30, already altered to solution) which i solved by adding the ./ in front of it and giving the software permission to use the script file.
My current issue with the code/command line is the following error:
Use of uninitialized value $e2 in string eq at ./clean_htseq.pl line 18.
find: warning: Unix filenames usually don't contain slashes (though pathnames do). That means that '-name ‘*./SRR7251667.c’' will probably evaluate to false all the time on this system. You might find the '-wholename' test more useful, or perhaps '-samefile'. Alternatively, if you are using GNU grep, you could use 'find ... -print0 | grep -FzZ ‘*./SRR7251667.c’'.
This has been tracked down to the "__" at the end of the command line, while i'm sure this is supposed to mean something to the script I removed it and resulted in the following error:
Use of uninitialized value $stop in concatenation (.) or string at clean_htseq.pl line 30.
./clean_htseq.pl ./SRR7251667.c > ./SRR7251667.c2
Use of uninitialized value $e1 in string eq at ./clean_htseq.pl line 18.
Use of uninitialized value $e2 in string eq at ./clean_htseq.pl line 18.
Use of uninitialized value $e1 in concatenation (.) or string at ./clean_htseq.pl line 18.
Use of uninitialized value $e2 in concatenation (.) or string at ./clean_htseq.pl line 18.
eq at ./clean_htseq.pl line 18.
An error occurs too when I remove the "." from "./" but it comes back with an error about not finding the _clean_htseq.pl_ file which is in the working directory.
Your problem seems to be here:
my $dir = shift;
my $e1 = shift;
my $e2 = shift;
my $stop = shift;
Outside of a subroutine, shift works on #ARGV—the array that holds the command line arguments. You shift four times, so you need four arguments:
perl clean_htseq.pl ./ c c2 __
You only seem to give it two, and $stop has no value (so you are giving it less than two):
./clean_htseq.pl $stop $f
You can't just remove arguments and hope things still work out. Likely you're going to have to look at the source to see what those things mean (which should motivate you as a scientist to use good variable names and document code—Best Practices for Scientific Computing).
A first step may be to set defaults. The defined-or operator does well here:
use v5.10;
my $dir = shift // 'default_dir';
my $e1 = shift // 'default_value';
my $e2 = shift // 'default_value';
my $stop = shift // 'default_value';
Or, you could just give up if there aren't enough arguments. An array in scalar context gives you the number of elements in the array (although it doesn't guarantee anything about their values):
die "Need four arguments!\n" unless #ARGV == 4;
There are various other improvements which would help this script, some of which I go through in the "Secure Programming Techniques" chapter in Mastering Perl. Taking unchecked user input and passing it to another program is generally not a good idea.
This throws an error in Perl v5.20:
use strict;
use warnings;
my #a = (2,3,9);
my %b = map { "number $_" => 2*$_ } #a;
Error:
syntax error at a.pl line 4, near "} #a"
Execution of a.pl aborted due to compilation errors.
This doesn't:
use strict;
use warnings;
my #a = (2,3,9);
my %b = map { "number ".$_ => 2*$_ } #a;
Why is interpolation of $_ disallowed within the map BLOCK?
map has two syntax:
map BLOCK LIST
map EXPR, LIST
Perl must determine which syntax you are using. The problem is that both BLOCK and EXPR can start with { because { ... } can be the hash constructor (e.g. my $h = { a => 1, b => 2 };).
That means that Perl's grammar is ambiguous. When an ambiguity is encountered, perl guesses what you mean after looking ahead a little. In your situation, it guessed wrong. It guessed { was the start of a hash constructor instead of the start of a block. You will need to disambiguate explicitly.
The following are convenient ways to disambiguate blocks and hash constructors:
+{ ... } # Not a valid block, so must be a hash constructor.
{; ... } # Perl looks head, and sees that this must be a block.
So in your case, you could use
my %b = map {; "number $_" => 2*$_ } #a;
Related: Difference between returning +{} or {} in perl from a function, and return ref or value
The following code does not print the 'HASH' type. What is wrong with this code ?
#! /usr/bin/perl
$prices{'pizza'} = 12.00;
$prices{'coke'} = 1.25;
$prices{'sandwich'} = 3.00;
print ref($prices);
First of all, you should put use strict; and use warnings; at the top of your script (and do that for all the future Perl code as well). After doing so, you will see the following:
Global symbol "%prices" requires explicit package name at ./a.pl line 4.
Global symbol "%prices" requires explicit package name at ./a.pl line 5.
Global symbol "%prices" requires explicit package name at ./a.pl line 6.
Global symbol "$prices" requires explicit package name at ./a.pl line 7.
Execution of ./a.pl aborted due to compilation errors.
What it means is that you tried to use to separate variables: a %prices hash and a $prices scalar.
After fixing variable declaration using my %prices;, you can get a reference to your %prices hash as follows:
my $prices_ref = \%prices;
print ref($prices_ref);
From formal standpoint, the answer may be shorter:
ref($prices) would return 1 if $prices value were a reference to another variable or false otherwise.
ref($prices) is the first use of an undeclared variable $prices (previous lines refer to another undeclared variable - hash %prices).
The value of $prices is undef and ref($prices) is an empty string.
Probably, your idea was to write
$prices->{'pizza'} = 12.00;
$prices->{'coke'} = 1.25;
$prices->{'sandwich'} = 3.00;
print ref($prices);
Why doesn't the first example output a warning?
#!/usr/bin/env perl
use warnings;
use 5.012;
my $c = "9\n";
say $c * 2;
my $d = "6a";
say $d * 2;
# 18
# Argument "6a" isn't numeric in multiplication (*) at ./perl8.pl line 9.
# 12
When converting a number from a string, trailing whitespace is ignored, and newline counts as whitespace, so a warning isn't generated. Converting "9 " doesn't generate a warning either.
Because Perl thinks it's a number:
use Scalar::Util 'looks_like_number';
for ("9\n", "6a") {
say looks_like_number($_);
}
1
0
How might this block of code in Date/Manip.pm from the Date::Manip module:
#*Get rid of a problem with old versions of perl
no strict "vars";
# This sorts from longest to shortest element
sub sortByLength {
return (length $b <=> length $a);
}
use strict "vars";
I get this warning:
Use of uninitialized value in length at /perl/lib/perl5.8/Date/Manip.pm line 244.
The problem is not actually located there; the function is just being called with invalid (undef) parameters. To get a better trace of where it came from, try this:
$SIG{__WARN__} = sub {
require Carp;
Carp::confess("Warning: $_[0]");
};
This will print a stacktrace for all warnings.
Either $a or $b are undef. Check the list you are feeding to the sort that uses this subroutine to see if you have an undefined value.
How are you using this code?
If warnings for uninitialized diagnostics were enabled (perhaps via blanket -w or use warnings;) and if sortByLength were somehow called as a normal subroutine, rather than as a sort {} function, you would likely see this error:
$ perl -Mwarnings=uninitialized -e 'sub sbl { (length $b <=> length $a) } sbl'
Use of uninitialized value in length at -e line 1.
Use of uninitialized value in length at -e line 1.
Here I get two warnings, because both $a and $b are uninitialized. Hard to say without more context.