Trying to use eval to check for a perl module [duplicate] - perl

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How can I check if I have a Perl module before using it?
I'd like to eval a use statement similar to this: eval {use $foo;} but am having trouble with the correct syntax. I've tried various combinations of string interpolation, but the eval always succeeds even for a module that does not exist. Can someone give me hand with this one?

The idiom you are looking for is:
eval "use $module; 1" or ... ;
eval "use $module; 1" or warn "$module is not available: $#";
eval "use $module; 1" or die "This script requires $module";
eval "use $module; 1" or $module_available = 0;
eval "always succeeds" in the sense that program execution will continue no matter what code is evaluated -- that's really the whole point of an eval statement. If the evaluated string contained errors -- run time or compile time -- the return value of the eval call is undef and the special variable $# will be set with an appropriate error message.
The use statement, even when successful, does not return a value. That's why this idiom includes the "; 1" at the end.

use is a keyword that is processed during compilation, as is mentioned in the comments, it does require you to use bareword arguments. That is, no variables.
Now, I can't get an eval { use $foo } to even compile, because it causes a syntax error, so the script is never run. I'm not sure what you mean exactly by "always succeeds", unless you mean the opposite: "always fails".

Related

perlcritic: eval "require $module";

While digging in some old source code I saw the following:
my $module = $some{module};
eval "require $module";
die "Bad module\n$#" if $#;
while I understand what the code does, it tries "require" a module and die when it is unsuccessful - the perlcritic complains about it
Expression form of "eval" at line 331, column 13. See page 161 of
PBP. (Severity: 5)
Unfortunately I havent the PBP book, so wondering what is the correct method of the above...
Also, in the same source found:
sub test_repo_file {
my($self, $repo, $test) = #_;
my $abspath = repo_abs_path($repo);
return "eval -$test $abspath";
}
Here doesn't understand what solves the "eval", and the perlcritic complains again for the "string eval"...
Can somebody please explain the basic points about the "string eval" and how to write the above correctly?
Running perlcritic --verbose '%d\n' will give you the explanations, too:
The string form of `eval' is recompiled every time it is executed,
whereas the block form is only compiled once. Also, the string form
doesn't give compile-time warnings.
eval "print $foo"; # not ok
eval {print $foo}; # ok
It's applicable to the first case.
The second case doesn't generate any messages for me. Isn't it rather
return eval "-$test $abspath"
You can't use block eval here. You should verify that $test really contains what it should
$test =~ /^[a-z]$/i
and avoid the evaluation of $abspath:
eval "-$test \$abspath"
If you're OK with that, you can than add
## no critic
to the end of the line.
Few users should ever have to use eval EXPR. Most of the time, it's being used as a template system when it shouldn't (e.g. s/.../eval($repl)/e), or it's used to catch exceptions when eval BLOCK should have been used.
If there is reason to use it, it's to execute generated code or user-submitted code. Generating code is tricky and error-prone, and errors have security implications. Executing user-submitted code is a major security concern. As such, every use of eval EXPR should be carefully reviewed.
It's quite appropriate for perlcritic to flag its usage given that virtually every use is an error with major security implications.
In your case, the use of eval EXPR is suboptimal. I'd use
my $path = $module . ".pm";
$path =~ s{::}{/}g;
eval { require $path }
Yes, this is portable.

Make Perl warn me about missing unused functions [duplicate]

This question already has answers here:
How do I get perl -c to throw Undefined or Undeclared function errors?
(4 answers)
Closed 8 years ago.
perl -wle 'if (0) {no_such_func()}'
The above runs without errors, despite the -w, because no_such_func()
is never called.
How do I make Perl check all functions/modules I reference, even ones
I don't use?
In a more realistic case, some functions may only be called in special
cases, but I'd still like to make sure they exist.
EDIT: I installed perlcritic, but I think I'm still doing something wrong. I created this file:
#!/bin/perl -w
use strict;
if (0) {no_such_func();}
and perlcritic said it was fine ("source OK"). Surely static analysis could catch the non-existence of no_such_func()? The program also runs fine (and produces no output).
You can't do it because Perl doesn't see if functions exist until runtime. It can't. Consider a function that only gets evaled into existence:
eval 'sub foo { return $_[0]+1 }';
That line of code will create a subroutine at runtime.
Or consider that Perl can use symbolic references
my $func = 'func';
$func = "no_such_" . $func;
&$func;
In that case, it's calling your no_such_func function, but you can't tell via static analysis.
BTW, if you want to find functions that are never referenced, at least via static analysis, then you can use a tool like Perl::Critic. See http://perlcritic.com/ or install Perl::Critic from CPAN.
Hmm, this is difficult: When Perl parses a function call, it doesn't always know whether that function will exist. This is the case when a function is called before it's declared:
foo();
sub foo { say 42 }
Sometimes, the function may only be made available during runtime:
my $bar = sub { say 42 };
my $baz = sub { say "" };
*foo = rand > 0.5 ? $bar : $baz;
foo();
(I'd like to mention the “Only perl can parse Perl” meme at this point.)
I'm sure you could hack the perl internals to complain when the function can't be resolved before run time, but this is not really useful considering the use cases above.
You can force compile-time checks if you call all subs without parentheses. So the following will fail:
$ perl -e 'use strict; my $condvar; if ($condvar) {no_such_func}'
Bareword "no_such_func" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
(However, it does not fail if you write if (0), it seems that perl's optimizer is removing the whole block without checking any further)
This has the consequence that you have to define all subroutines before using them. If you work like this, then sometimes "forward" declarations are necessary. But then it's possible that a forward declaration never gets a definition, which is another possible error case.

What is $# in Perl?

I have a Perl script which I cannot understand.
for $i(#myarr)
{
#some stuff
eval {
#some stuff
};
if($#)
{
print "*** $# ****";
}
}
What does that eval do? Is it a standard Perl command or just some sub?
What is the variable $#? It is currently printing a string but I don know where that string is coming from.
$# The Perl syntax error or routine error message from the last eval, do-FILE, or require command. If set, either the compilation failed, or the die function was executed within the code of the eval. please read this doc http://perldoc.perl.org/perlvar.html
To add to Suic’s answer, see the English module that lets you use more descriptive $EVAL_ERROR instead of $# and the Try::Tiny or TryCatch modules that avoid common traps associated with using eval for exception handling. Also, the next time you wonder about a Perl function, perldoc -f is your friend (like perldoc -f eval).

Why doesn't Perl warn for the redeclaration of a my() variable in the same scope?

use strict;
my $world ="52";
my $in = "42" ;
my $world="42";
my $out = "good" ."good";
chop($out);
print $out;
Do not worry about the code.The question is that I used my $world in two different lines but compiler didn't give any error but if we consider C language's syntax then we will get the error because of the redeclaration of variable. Why don't perl gives any error for redeclaration. I have one more question: What is the size of a scalar variable ?
1/ Variable redeclaration is not an error. Had you included "use warnings" then you would get a warning.
2/ By "size of scalar variable" do you mean the amount of data that it can store? If that's the case, Perl imposes no arbitrary limits.
You seem to be posting a lot of rather simple questions very quickly. Have you considered reading "Learning Perl"?
The question is my $world i used it in two different lines but compiler said no error but to the c we get error as redclaration of variable but why not in perl.
Simply because Perl isn't C, and redefining a variable isn't an error condition.
It can be a cause of unexpected behaviour though and would be picked up if you had use warnings; (as has been suggested to you before).
What is the size of scalar variable ? is there any size?
Define 'size'. Bytes? Characters? Something else? You might be looking for length
Because Perl likes to be robust. If you had warnings turned on, you would have heard about it.
"my" variable $world masks earlier declaration in same scope at - line 7.
Although USUW (use strict; use warnings;) is a good development practice, so would be using autodie--if autodie worried about syntax warnings. But the following, concept is roughly the same, to make sure that you're not avoiding any warnings.
BEGIN { $SIG{__WARN__} = sub { die #_; }; }
The above code creates a signal handler for warnings that just dies instead. However, I think this is better for a beginner:
BEGIN {
$SIG{__WARN__}
= sub {
eval {
# take me out of the chain, to avoid recursion
delete $SIG{__WARN__};
# diag will install the warn handler we want to use.
eval 'use diagnostics;';
$SIG{__WARN__}->( #_ ); # invoke that handler
};
exit 1; # exit regardless of errors that might have cropped up.
};
}
Anywhere you want, you can tell perl that you are not interested in changing your code to issue a particular category of warnings (and diagnostics will tell you the category!) and if you explicitly tell perl no warnings 'misc', not only will it not warn you, but it will also not fire off the warning handler, which kills the program.
This will give you a more c-like feel--except that c has warnings too (so you could implement a lexical counter as well...oh well.)

How can I eval environment variables in Perl?

I would like to evaluate an environment variable and set the result to a variable:
$x=eval($ENV{EDITOR});
print $x;
outputs:
/bin/vi
works fine.
If I set an environment variable QUOTE to \' and try the same thing:
$x=eval($ENV{QUOTE});
print $x;
outputs:
(nothing)
$# set to: "Can't find a string terminator anywhere before ..."
I do not wish to simply set $x=$ENV{QUOTE}; as the eval is also used to call a script and return its last value (very handy), so I would like to stick with the eval(); Note that all of the Environment variables eval'ed in this manner are set by me in a different place so I am not concerned with malicious access to the environment variables eval-ed in this way.
Suggestions?
Well, of course it does nothing.
If your ENV varaible contains text which is half code, but isn't and you give the resulting string to something that evaluates that code as Perl, of course it's not going to work.
You only have 3 options:
Programmatically process the string so it doesn't have invalid syntax in it
Manually make sure your ENV variables are not rubbish
Find a solution not involving eval but gives the right result.
You may as well complain that
$x = '
Is not valid code, because that's essentially what's occurring.
Samples of Fixing the value of 'QUOTE' to work
# Bad.
QUOTE="'" perl -wWe 'print eval $ENV{QUOTE}; print "$#"'
# Can't find string terminator "'" anywhere before EOF at (eval 1) line 1.
# Bad.
QUOTE="\'" perl -wWe 'print eval $ENV{QUOTE}; print "$#"'
# Can't find string terminator "'" anywhere before EOF at (eval 1) line 1.
# Bad.
QUOTE="\\'" perl -wWe 'print eval $ENV{QUOTE}; print "$#"'
# Can't find string terminator "'" anywhere before EOF at (eval 1) line 1.
# Good
QUOTE="'\''" perl -wWe 'print eval $ENV{QUOTE}; print "$#"'
# '
Why are you eval'ing in the first place? Should you just say
my $x = $ENV{QUOTE};
print "$x\n";
The eval is executing the string in $ENV{QUOTE} as if it were Perl code, which I certainly hope it isn't. That is why \ disappears. If you were to check the $# variable you would find an error message like
syntax error at (eval 1) line 2, at EOF
If you environment variables are going to contain code that Perl should be executing then you should look into the Safe module. It allows you to control what sort of code can execute in an eval so you don't accidentally wind up executing something like "use File::Find; find sub{unlink $File::Find::file}, '.'"
Evaluating an environment value is very dangerous, and would generate errors if running under taint mode.
# purposely broken
QUOTE='`rm system`'
$x=eval($ENV{QUOTE});
print $x;
Now just imagine if this script was running with root access, and was changed to actually delete the file system.
Kent's answer, while technically correct, misses the point. The solution is not to use eval better, but to not use eval at all!
The crux of this problem seems to be in understanding what eval STRING does (there is eval BLOCK which is completely different despite having the same name). It takes a string and runs it as Perl code. 99.99% this is unnecessary and dangerous and results in spaghetti code and you absolutely should not be using it so early in your Perl programming career. You have found the gun in your dad's sock drawer. Discovering that it can blow holes in things you are now trying to use it to hang a poster. It's better to forget it exists, your code will be so much better for it.
$x = eval($ENV{EDITOR}); does not do what you think it does. I don't even have to know what you think it does, that you even used it there means you don't know. I also know that you're running with warnings off because Perl would have screamed at you for that. Why? Let's assume that EDITOR is set to /bin/vi. The above is equivalent to $x = /bin/vi which isn't even valid Perl code.
$ EDITOR=/bin/vi perl -we '$x=eval($ENV{EDITOR}); print $x'
Bareword found where operator expected at (eval 1) line 1, near "/bin/vi"
(Missing operator before vi?)
Unquoted string "vi" may clash with future reserved word at (eval 1) line 2.
Use of uninitialized value $x in print at -e line 1.
I'm not sure how you got it to work in the first place. I suspect you left something out of your example. Maybe tweaking EDITOR until it worked?
You don't have to do anything magical to read an environment variable. Just $x = $ENV{EDITOR}. Done. $x is now /bin/vi as you wanted. It's just the same as $x = $y. Same thing with QUOTE.
$ QUOTE=\' perl -wle '$x=$ENV{QUOTE}; print $x'
'
Done.
Now, I suspect what you really want to do is run that editor and use that quote in some shell command. Am I right?
Well, you could double-escape the QUOTE's value, I guess, since you know that it's going to be evaled.
Maybe what you want is not Perl's eval but to evaluate the environment variable as the shell would. For this, you want to use backticks.
$x = `$ENV{QUOTE}`