fping Script Described in Man Page has Syntax Error - perl

I'm trying to run the fping script described in its man page.
#!/usr/local/bin/perl
require 'open2.pl';
$MAILTO = "root";
$pid = &open2("OUTPUT","INPUT","/usr/local/bin/fping -u");
#check=("slapshot","foo","foobar");
foreach(#check) { print INPUT "$_\n"; }
close(INPUT);
#output=;
if ($#output != -1) {
chop($date=`date`);
open(MAIL,"|mail -s 'unreachable systems' $MAILTO");
print MAIL "\nThe following systems are unreachable as of: $date\n\n";
print MAIL #output;
close MAIL;
}
However, I get the following error from anywhere I run it:
syntax error at /path/to/pingtest.pl line 13, near "=;"
Execution of /path/to/pingtest.pl aborted due to compilation errors.
Can someone help me what's wrong with line 13? I have open2.pl and fping path is correct.

If you have found the script on the online man-page, then <OUTPUT> has been interpreted as HTML markup and deleted. It should read
#output = <OUTPUT>;
But this Perl script looks like it was written decades ago
The use of require open2.pl was long-ago replaced by use IPC::Open2
It does not use use strict or use warnings, and avoids lexical variables
Function calls use the arcane &open2 syntax, which is useful only in very special cases
The calls to open use the old-fashioned and ambiguous two-argument-version

Related

Perl Script (for calling Mac::AppleScript Perl module)

I'm setting up some automation using shell and applescript scripting. Several of my modules require passing several params into the AppleScript. Although there are a few ways of doing so, a bit of research lead me to the "Mac::AppleScript Perl module" and it looks really promising. However it requires a short .pl script in /usr/local/bin. The only example of it I found has two syntax errors and I have absolutely no experience at all in Perl.
I've tried guessing at what might be throwing the errors based on what I would use in the languages I've worked with but even though I can recognize the variables not expanding in a few spots, my attempts at correcting it results in further errors and I've been hacking at it for hours. Can someone please take a look and tell me what might be the syntax issues I can fix?
#!/usr/bin/perl
use strict;
use Mac::AppleScript qw/ RunAppleScript /;
if( $#ARGV = 0) ? '"'.join('","',#ARGV).'"' : "";
my $rtn = RunAppleScript( "return run script alias ((POSIX file ""
.$script.'") as text) with parameters {'.$args.'}' ),"n"
or die "AppleScript Error: $!";
$rtn =~ s/(^"|"$)//g;
print $rtn,"n";
Problems:
You have an unescaped " in your double-quoted string literal.
You use variables you never declared or initialized.
You have a stray ,"n" in your code.
Your code suffers from code injection bugs.
The error message is found in $#, not $!.
Fixed:
sub text_to_as_lit { '"'.( $_[0] =~ s/([\\"])/\\$1/rg ).'"' } #'
my ($script, #args) = #ARGV;
my $rtn = RunAppleScript(sprintf(
"return run script alias ((POSIX file %s) as text) with parameters {%s}",
text_to_as_lit($script),
( join ',', map text_to_as_lit($_), #args ),
))
or die("AppleScript Error: $#");
Untested.

Perl - error reading text file

I am trying to read a file in perl.
I just want to print the names of each line of file players.txt.
I am using this code:
#!/usr/local/bin/perl
open (MYFILE, 'players.txt');
while () {
chomp;
print "$_\n";
}
close (MYFILE);
This produces this error:
./program5.pl: line 2: syntax error near unexpected token `MYFILE,'
./program5.pl: line 2: ` open (MYFILE, 'players.txt');'
I am using a Unix operation system to do this. I can't find a guide that works for reading in a file in Perl.
The errors you're getting are bash errors, which means that you're asking bash to process Perl code. That isn't going to work
At a guess, your shebang line #!/usr/local/bin/perl doesn't start at the beginning of the very first line. The two characters #! must be the first two bytes of the file
Alternatively you can drop the shebang line if you specify that perl should run the program:
perl program5.pl
You also have an error in while (), which is an endless loop and doesn't read from the file. You need
while ( <MYFILE> ) {
...
}
You have found a very poor and old-fashioned source of advice to learn Perl. I suggest you take a look at the
Perl tag information
which has a list of many excellent tutorials and resources

in perl, 'use strict' disables important warnings

Adding use strict to a perl program disables an important warning message. Is this a bug in perl?
This little program has a problem
#!/usr/bin/perl -w
my $rule;
sub applyRule() {
eval $rule;
}
my $foo_bar;
$foo_bar = "mega-foo-bar-ness";
$rule = 's/#FOO_BAR/$foo_bar/g';
$_ = "Please replace #FOO_BAR with something.";
applyRule();
print STDERR "OUTPUT: $_\n";
and we get a helpful warning message when running that program:
$ ./test1.pl
Use of uninitialized value $foo_bar in substitution (s///) at (eval 1) line 1.
OUTPUT: Please replace with something.
Now add use strict;
#!/usr/bin/perl -w
use strict;
my $rule;
sub applyRule() {
eval $rule;
}
my $foo_bar;
$foo_bar = "mega-foo-bar-ness";
$rule = 's/#FOO_BAR/$foo_bar/g';
$_ = "Please replace #FOO_BAR with something.";
applyRule();
print STDERR "OUTPUT: $_\n";
The substitution just silently fails.
$ ./test1.pl
OUTPUT: Please replace #FOO_BAR with something.
When I have mysterious errors in perl should I always try removing use strict to see if I get some helpful warnings?
edit 1 stackoverflow is asking me to describe why this is not a duplicate of Why use strict and warnings?. This is a case where adding use strict results in fewer warnings, which makes debugging harder -- the opposite of what I expect use strict would do; the opposite of what is suggested in the answers to that question:
The pragmas catch many errors sooner than they would be caught otherwise, which makes it easier to find the root causes of the errors.
edit 2: For anyone else seeing this: another way is:
defined (eval $rule) or warn "eval error: $#\n";
because eval returns undefined if there is an error. The Programming Perl book states in the section about eval
If there is a syntax error or run-time error, eval returns the undefined value and puts the error message in $#. If there is no error, $# is guaranteed to be set to the null string, so you can test it reliably afterward for errors.
Note however that with versions prior to Perl 5.14 there can be problems relying on '$#`.
Instead of a warning, it throws an exception. And you aren't testing to see if eval gave an exception.
Try:
eval "$rule; 1" or warn "exception thrown: $#\n";

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.

Debugging perl script

I don't know perl, but I need to debug a perl script which is needed by an application I am using, this is the error I get:
Unable to recognise encoding of this document at /usr/lib/perl5/vendor_perl/5.8.8/XML/SAX/PurePerl/EncodingDetect.pm line 9
The thing is, this script cannot figure out what is the encoding of a file. What I am trying to find out is, which file is that. I couldn't be able to find a way to stack trace. Here is the script trimmed a little:
package XML::SAX::PurePerl; # NB, not ::EncodingDetect!
use strict;
sub encoding_detect {
my ($parser, $reader) = #_;
my $error = "Invalid byte sequence at start of file";
my $data = $reader->data;
if ($data =~ /^\x00\x00\xFE\xFF/) {
# BO-UCS4-be
$reader->move_along(4);
$reader->set_encoding('UCS-4BE');
return;
} .. tons of if else statements
warn("Unable to recognise encoding of this document");
return;
I checked, but this reader object doesn't have a name, or path attribute. I have a control over this script, so I may modify it if necessary. Any help is appreciated.
Edit: I have tracked down the problem until this line in the application I'm trying to use:
my #array = SystemImager::HostRange::expand_groups($clients);
If you use the Carp module and the confess method, you get a stack backtrace:
use Carp;
confess "Something went horribly wrong" if ($something == $wrong);
This is of most use inside a function (in a module), but it helps. However, it sounds as if the error is being reported by code you're using, so you may not be able to get it to croak for you, but you should read the manual for Carp, which says in part:
Forcing a Stack Trace
As a debugging aid, you can force Carp to treat a croak as a confess and a carp as a cluck across all modules. In other words, force a detailed stack trace to be given. This can be very helpful when trying to understand why, or from where, a warning or error is being generated.
This feature is enabled by 'importing' the non-existent symbol 'verbose'. You would typically enable it by saying
perl -MCarp=verbose script.pl
or by including the string -MCarp=verbose in the PERL5OPT environment variable.
Alternat[iv]ely, you can set the global variable $Carp::Verbose to true.
As suggested by daxim in a comment, also consider Carp::Always:
use Carp::Always;
makes every warn() and die() complain loudly in the calling package and elsewhere. More often used on the command line:
perl -MCarp::Always script.pl
The pure Perl implementation of XML::SAX::PurePerl is marked as 'slow' by its maintainer. You should perhaps look at using one of the many other XS-based SAX modules, especially one that provides automatic encoding detection.
To debug perl script you may use:
perl -d:DebugHooks::Terminal script.pl
Look at this