Compilation error wile using pod2usage in perl - perl

I have a file which accepts a file as an argument and does some operation on it.
#!/usr/bin/perl
use strict;
use warnings;
use Date::Format;
use Pod::Usage;
###################
#USAGE
###################
=head1 SYNOPSIS
perl my-file.pl <log file name>
Options:
-help Prints usage synopsis of this program.
-man Man page for this program.
Use option "-man" for extended usage help.
=head1 ARGUMENTS
=over 1
=item 1 Log File Name
Enter name of the log file. This is a required argument.
=cut
print "\n\n";
GetOptions('help|?' => \$help, man => \$man) or pod2usage(2);
pod2usage(1) if $help;
pod2usage(-verbose => 2) if $man;
pod2usage("$0: Insufficient arguments given. Please see the usage below...") if (#ARGV == 0);
my $logfile = $ARGV[0];
my $cmd;
my $n;
$cmd = q(awk '!/Jobs still running./' $logfile > temp.txt && mv temp.txt $logfile);
$n = system($cmd)
;
While running this file I am getting the below compilation error. Not sure what is the reason for this error as another file with similar format work fine.
Global symbol "$help" requires explicit package name at mv-workitem-LogWatcher.pl line 33.
Global symbol "$man" requires explicit package name at mv-workitem-LogWatcher.pl line 33.
Global symbol "$help" requires explicit package name at mv-workitem-LogWatcher.pl line 34.
Global symbol "$man" requires explicit package name at mv-workitem-LogWatcher.pl line 35.
my-file.pl had compilation errors
.

You turned on strict but failed to declare your variables. You usually do this with my. Here's some more about my and lexical scoping of variables.
I'd recommend picking up a copy of Modern Perl or Beginning Perl.

You are getting errors because you are using use strict in your code but you didn't declare any varibale.
To understand variable declaration read this tutorial Variable declaration in Perl.

Related

How to call a perl script from another perl script and transfer parameter?

I'm trying to call a perl script from another perl script, and transfer the parameter to it.
For example:
there is a script: main.pl
I use command line to run this script, and give a value to parameter "$directory", then I call another perl script "sub.pl". I want to pass the value of "$directory" to the parameter "$path" from sub.pl.
(in brief, sub.pl has the parameter $path, main.pl has the parameter $directory, I want to call sub.pl in main.pl, and pass the $directory value to $path)
Sorry for my verbose description...Anyway, which function can do this job? Thanks.
You did not provide any sample of code you have tried -- how can we know what is your vision of the code?
Ok, bellow I provide a sample of main script dir_main.pl and secondary script dir_sub.pl just for demonstration purpose how I would do it.
Both scripts can be run with parameters '--help' (-h) or '--man' (-m) to obtain help and man page describing usage and full documentation for the scripts. Script dir_sub.pl has extra option '--debug' (-d) to print content of options hash.
USAGE: perl dir_main.pl --dir c:\Users -- Windows
USAGE: dir_main.pl --dir /usr/home -- Linux
NOTE:
in Linux both scripts should be made executable with following command chmod og+x dir_main.pl dir_sub.pl before they can run from shell without specifying perl
(shell knows from shebang that the scripts should be run with perl interpreter)
Source code of: dir_main.pl
#!/usr/bin/perl
#
# DESCRIPTION:
# Sample code 'dir_main.pl' written for StackOverflow
#
# DATE:
# Jan 10, 2020
#
# AUTHOR:
# Polar Bear <https://stackoverflow.com/users/12313309/polar-bear>
#
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
use Pod::Usage;
my %opt;
GetOptions(
'dir|d=s' => \$opt{dir},
'help|h' => \$opt{help},
'man|m' => \$opt{man}
) or pod2usage(2);
pod2usage(1) if $opt{help};
pod2usage(-exitval => 0, -verbose => 2) if $opt{man};
system('perl','.\dir_sub.pl','--path',$opt{dir}) if $opt{dir};
exit 0;
=pod
=head1 NAME
program.pl - short description of the program
=head1 SYNOPSIS
program.pl [options]
Options:
--dir,-d input directory
--help,-h brief help message
--man,-m full documentation
=head1 OPTIONS
=over 4
=item B<--dir|-d>
Input directory
=item B<--help|-h>
Print a brief help message and exit
=item B<--man|-m>
Prints the manual page and exit
=back
=head1 DESCRIPTION
B<This program> surve some purpose to produce pre-defined result
=head1 AUTHOR
Polar Bear Jan 10, 2020
=head1 REPORTING BUGS
E-mail L<mailto:bugs#inter.net>
=head1 COPYRIGHT
Copyright information
=head1 SEE ALSO
L<The Perl Home page|http://www.perl.org/>
=cut
Source code of: dir_sub.pl
#!/usr/bin/perl
#
# DESCRIPTION:
# Sample code 'dir_sub.pl' written for StackOverflow
#
# DATE:
# Jan 10, 2020
#
# AUTHOR:
# Polar Bear <https://stackoverflow.com/users/12313309/polar-bear>
#
use strict;
use warnings;
use feature 'say';
use Getopt::Long qw(GetOptions);
use Pod::Usage;
use Data::Dumper;
my %opt;
GetOptions(
'path|p=s' => \$opt{path},
'help|h' => \$opt{help},
'man|m' => \$opt{man},
'debug|d' => \$opt{debug}
) or pod2usage(2);
pod2usage(1) if $opt{help};
pod2usage(-exitval => 0, -verbose => 2) if $opt{man};
print Dumper(\%opt) if $opt{debug};
list($opt{path}) if $opt{path};
sub list {
my $path = shift;
opendir my $dh, $path
or die "ERROR: opendir couldn't open $path";
map{ say $_ } readdir($dh);
close $dh;
}
exit 0;
=pod
=head1 NAME
program.pl - short description of the program
=head1 SYNOPSIS
program.pl [options]
Options:
--path,-p input path to list
--help,-h brief help message
--man,-m full documentation
--debug,-d debug information
=head1 OPTIONS
=over 4
=item B<--path|-p>
Input path to list files
=item B<--help|-h>
Print a brief help message and exit
=item B<--man|-m>
Prints the manual page and exit
=item B<--debug|-d>
Prints the debug information
=back
=head1 DESCRIPTION
B<This program> surve some purpose to produce pre-defined result
=head1 AUTHOR
Polar Bear Jan 10, 2020
=head1 REPORTING BUGS
E-mail L<mailto:bugs#inter.net>
=head1 COPYRIGHT
Copyright information
=head1 SEE ALSO
L<The Perl Home page|http://www.perl.org/>
=cut
Very first question: does sub.pl have a mechanism for setting $path from the command-line?
If not, you're not going to do it: you can't arbitrarily set an internal variable to some value... that would open up all sorts of security risks & dangers to any piece of code!
Assuming you can call something like sub.pl path=/my/path then it's easy
(but I have horrible suspicion you mean the former!)

How to pass command line arguments along with perl modules using perl?

I treid one of my previous example to pass input and output files via command line arguments using perl?
Previous example:
[Is it possible to add the file out in the File::Find::Rule using perl?
code which i tried to add input and output file as command line arguments:(generate.pl).I got struck how to include command line arguments to read and copy the files along with perl modules.
use strict;
use warnings 'all';
use CGI qw(:all);
#generate the user file arguments
use Getopt::Long 'GetOptions';
use File::Path qw( make_path );
use File::Copy qw( copy move);
use File::Find::Rule qw( );
GetOptions(
'prjroot=s' => \my $input_dir,
'outdir=s' => \my $output_dir,
);
my %created;
for my $in (
File::Find::Rule
->file()
->name(qr/^[^.].*\.yfg$/)
->in($input_dir)
) {
my $match_file = substr($in, length($input_dir) + 1);
my ($match_dir) = $match_file =~ m{^(.*)/} ? $1 : '.';
my $out_dir = $output_dir . '/' . $match_dir;
my $out = $output_dir . '/' . $match_file;
make_path($out_dir) if !$created{$out_dir}++;
copy($in, $out);
}
Error occured:
./generate.pl: line 1: use: command not found
./generate.pl: line 2: use: command not found
./generate.pl: line 3: syntax error near unexpected token `('
./generate.pl: line 3: `use CGI qw(:all);'
perl execution should be as follows:
I should copy the contents from one directory to another directory along with perl modulES(I.E File::Find::Rule)
./generate.pl -prjroot "/home/bharat/DATA" -outdir "/home/bharat/DATA1"
Help me fix my issues .
You miss the perl comment in the first line:
#!<path_to_perl>/perl
use strict;
use warnings 'all';
use CGI qw(:all);
#generate the user file arguments
.....
Your program will also work if you call it with the perl Interpreter in front of your command:
perl ./generate.pl -prjroot "/home/bharat/DATA" -outdir "/home/bharat/DATA1"
You've already seen what the problem is. But I'll just add that perldoc perldiag gives pretty good explanations for any error message you get from Perl. In this case, searching for "command not found" would give you this:
%s: Command not found
(A) You've accidentally run your script through csh or another shell instead of Perl. Check the #! line, or manually feed your script into Perl yourself. The #! line at the top of your file could look like
#!/usr/bin/perl -w
And that's particularly impressive, given that this error isn't actually generated by Perl - but by your shell.

Adding a help command to a script

Is there a standard way of adding a help function to a script? The simplest way would maybe to take an argument and print some text if it's "-help" or something. Does anyone have any examples on how to do this?
Thanks!
Consider Getopt::Long plus Pod::Usage. My usual pattern for writing CLI tools:
#!/usr/bin/env perl
# ABSTRACT: Short tool description
# PODNAME: toolname
use autodie;
use strict;
use utf8;
use warnings qw(all);
use Getopt::Long;
use Pod::Usage;
# VERSION
=head1 SYNOPSIS
toolname [options] files
=head1 DESCRIPTION
...
=cut
GetOptions(
q(help) => \my $help,
q(verbose) => \my $verbose,
) or pod2usage(q(-verbose) => 1);
pod2usage(q(-verbose) => 1) if $help;
# Actual code below
easy to use this :
if( $ARGV[0] eq '-h' || $ARGV[0] eq '-help')
{
help();
exit;
}
sub help { print "My help blah blah blah\n";
}
Take a look at https://github.com/qazwart/SVN-Watcher-Hook/blob/master/svn-watch.pl. I use a technique to combine the Getopt::Long module and the Pod::Usage module.
The main action occurs in lines 97 through 106 and in lines 108 through 110.
The Getopt::Long is a very common module to use since it handles command line arguments with easy. Using Pod documentation is rarer. However, all CPAN modules and all Perl built in modules use Pod documentation, so if you don't know it, learn it. POD is not very difficult to learn, and it's built into Perl, so all Perl programs can be self-documenting. You can print out the POD documentation of any program by using the perldoc command. Try this:
$ perldoc File::Find
You can also use the pod2html, pod2text and other types of translation commands to print POD documentation into HTML, etc.
Before I knew about POD, I would put something like this at the top of my program:
########################################################
# USAGE
#
my $USAGE =<<USAGE;
Usage:
foo [ -baz -fu <bar>] [-help]
where:
baz: yadda, yadda, yadda
fu: yadda, yadda, yadda
help: Prints out this helpful message
USAGE
#
######################################################
Then, in my program, I could do this:
if ($help) {
print "$USAGE\n";
exit 0;
}
This way, someone could look at the code and read the usage text. This would also be the same text that would print out when you used the -help parameter.
The way I do this is to utilise Getopt::Std to find an -h flag from the command line arguments.
use strict;
use warnings;
use Getopt::Std;
my %args;
getopts('h', \%args);
my $help = "help goes here. You can use
more than one line to format the text";
die $help if $args{h};
# otherwise continue with script...
A more sophisticated approach is to use POD::usage, although I have not tried this way personally.

Using Perl's Getopt::Long, how can I prevent the module from trying to match ambiguous option names?

I am using the Getopt::Long module to process command line arguments.
The typical behavior of this module is we could pass -f instead of full name of the variable --file. At the same time if I have another command line variable --find, and if I supply only -f at the command prompt, it would return with an error:
Option f is ambiguous (file, find).
I was wondering how can we curb such ambiguous usage?
Thanks in advance.
Have a look at the Getopt::Long documentation:
auto_abbrev
Allow option names to be abbreviated to uniqueness. Default is enabled
unless environment variable POSIXLY_CORRECT has been set, in which
case auto_abbrev is disabled.
Example:
use strict;
use warnings;
use Getopt::Long qw(:config no_auto_abbrev);
my ( $file, $fish );
GetOptions( "file=s" => \$file, "fish=s" => \$fish );
And the tests:
$ perl test.pl -fi 24
Unknown option: fi
$ perl test.pl -fis 24
Unknown option: fis
If you want to turn this auto abbreviation feature off you'll have to configure Getopt::Long using
use Getopt::Long qw(:config no_auto_abbrev) ;

My first perl script is generating an error

my perl script is:
#!/usr/bin/perl -w
use strict ;
use warnings;
print "Hello $name \n"
I get this error:
Global symbol "$name" requires explicit package name at fst_pscpt.pl.
This is really stopping my progress.do we need to include any packages???
Thanks & Regards,
B.Raviteja
You haven't declared any variable $name. So you'll need to get that variable somehow. For example, if you wanted to get it from the command line, you could do this:
#!/usr/bin/perl -w
use strict;
use warnings;
my $name = $ARGV[0];
print "Hello, $name!\n";
And then call your program like so:
./myprog.pl Rafe
And get the output:
Hello, Rafe!
Also, you don't have a semicolon at the end of the last line. You'll need that as well.
diagnostics gives you more useful help in this case:
$ perl -Mdiagnostics fst_pscpt.pl
Global symbol "$name" requires explicit package name at fst_pscpt.pl line 4.
Execution of fst_pscpt.pl aborted due to compilation errors (#1)
(F) You've said "use strict" or "use strict vars", which indicates
that all variables must either be lexically scoped (using "my"),
declared beforehand using "our", or explicitly qualified to say
which package the global variable is in (using "::").
Uncaught exception from user code:
Global symbol "$name" requires explicit package name at fst_pscpt.pl line 4.
Execution of fst_pscpt.pl aborted due to compilation errors.
at fst_pscpt.pl line 5
You need to declare $name when you use strict; (which includes strict vars). Just insert the line:
my $name;
before using it.