Using GetOptions to define a parameter that errors out when specified and input is missing but doesn't error out if parameter not specified at all? - perl

How do we define a CLI argument that errors out if we don't give an input but doesn't error out if we don't use that parameter at all?
Example : I invoke a program by:
perl program.pl --param1 input1
This should be an error:
perl program.pl --param1
But this should continue executing:
perl program.pl
Without giving --param1 should continue executing. Defining param1=s or param1:s in GetOptions don't differentiate between giving --param1 without input and not giving it at all ('=' case lets param1 be undef and ':' initializes to default value in both cases).

The requested behaviour is provided by =s.
#!/usr/bin/perl
use v5.14;
use Getopt::Long;
GetOptions( "param1=s" => \my $param1 )
or die "Usage\n";
say $param1 // "[undef]";
$ ./a.pl
[undef]
$ ./a.pl --param1 foo
foo
$ ./a.pl --param1
Option o requires an argument
Usage

Related

Is there a way to identify which perl specific options are passed to a script?

I'm aware a script can retrieve all the command line arguments passed to it through ARGV, i.e.:
# test.pl
print "$ARGV[0]\n";
print "$ARGV[1]\n";
print "$ARGV[2]\n";
## perl ./test.pl one two three
one
two
three
In the above example, the command line arguments passed to the test.pl script are "one", "two" and "three".
Now, suppose I run the following command:
## perl -d:DumpTrace test.pl one two three
or
## perl -c test.pl one two three
How can I tell from within the operations of the test.pl script that the options -c or -d:DumpTrace were passed to the perl interpreter?
I'm looking for a method that will identify when options are passed to the perl interpreter during the execution of a script:
if "-c" was used in the execution of `test.pl` script {
print "perl -c option was used in the execution of this script";
}
You can use Devel::PL_origargv to get access to to command line parameters that was passed to the perl interpreter. Example script p.pl:
use strict;
use warnings;
use Devel::PL_origargv;
my #PL_origargv = Devel::PL_origargv->get;
print Dumper({args => \#PL_origargv});
Then running the script like this for example:
$ perl -MData::Dumper -I. p.pl
$VAR1 = {
'args' => [
'perl',
'-MData::Dumper',
'-I.',
'p.pl'
]
};

Running a system command in a perl script that has "#" character

I have a system command like this :
unix_command "#output_file path_to_file"
Now when I try exec or system commands in a perl script I get this error :
Getting a string when expecting an operator.
Can you please help me how to do it in Perl.
Appreciate your help.
Thanks a ton!
Rakesh
system is really two different functions.
You can use it to launch a program.
The following syntax are used to launch a program:
system($prog, #one_or_more_args)
system({ $prog }, $arg0, #args)
Using one of these syntax, all strings passed as arguments are passed untouched to the child program.
Example usage:
system('perl', '-e', 'my #a = "foo"; print "#a\n";');
You can use it to execute a shell command.
The following syntax are used to execute a shell command:
system($shell_cmd)
The above is short for
system('/bin/sh', '-c', $shell_cmd)
You must provide a valid shell command. It you are building the command, you will need to take care to properly escape anything that needs escaping.
Example usage:
use String::ShellQuote qw( shell_quote );
my $cmd = shell_quote('perl', '-e', 'my #a = "foo"; print "#a\n";');
system($cmd);
A bit more specifically to your case, the shell command
program #file1 file2
can be executed as follows:
system('program', '#'.$file1, $file2);
If you actually need to construct a shell command (e.g. because you want to redirect output), you can use the following:
use String::ShellQuote qw( shell_quote );
my $cmd = shell_quote('program', '#'.$file1, $file2) . ' >output.txt 2>&1';
system($cmd);
If you don't need interpolation, use single quotes.
system 'echo #a';
If you do, use backslash.
system "echo \#a";

Compilation error wile using pod2usage in 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.

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) ;

How can I handle -r=<pattern> with Perl's Getopt::Long?

I am parsing command line options in Perl using Getopt::Long. I am forced to use prefix - (one dash) for short commands (-s) and -- (double dash) for long commands (e.g., --input=file).
My problem is that there is one special option (-r=<pattern>) so it is long option for its requirement for argument, but it has to have one dash (-) prefix not double dash (--) like other long options. Is possible to setup Getopt::Long to accept these?
By default, Getopt::Long interchangeably accepts either single (-) or double dash (--). So, you can just use --r=foo. Do you get any error when you try that?
use strict;
use warnings;
use Getopt::Long;
my $input = 2;
my $s = 0;
my $r = 3;
GetOptions(
'input=s' => \$input,
's' => \$s,
'r=s' => \$r,
);
print "input=$input\n";
print "s=$s\n";
print "r=$r\n";
These sample command lines produce the same results:
my_program.pl --r=5
my_program.pl --r 5
my_program.pl -r=5
my_program.pl -r 5
input=2
s=0
r=5
Are you setting "bundling" on?
If so, you can disable bundling (but then, you won't be able to do things like use myprog -abc instead of myprog -a -b -c).
Otherwise, the only thing that comes to mind right now is to use Argument Callback (<>) and manually parse that option.
#!/usr/bin/perl
use strict; use warnings;
use Getopt::Long;
my $pattern;
GetOptions('r=s' => \$pattern);
print $pattern, "\n";
Output:
C:\Temp> zz -r=/test/
/test/
C:\Temp> zz -r /test/
/test/
Am I missing something?