Using Data::Printer with qx operator - perl

I was experimenting with the Data::Printer module, and it worked fine until
I tried to print the return value of a system call using qx operator:
use strict;
use warnings;
use Data::Printer;
p qx/echo -n Hello/;
This gives me the following error:
Type of arg 1 to Data::Printer::p must be one of [#$%&] (not scalar)
I assume this error occurs because qx is not recognized as a scalar, hash, array, or function. So I tried:
p my $temp = qx/echo -n Hello/;
and it worked fine. The question is, if it is possible to avoid the use of the $temp variable? (I think this syntax would become annoying to use and remember in the long run)

Unlike Data::Dumper and Data::Dump, the default mode of Data::Printer allows you to display only the contents of variables, not arbitrary expressions
This behaviour can be circumvented by disabling the use_prototypes option in the use statement, when arrays and hashes must be passed explicitly by reference
use Data::Printer use_prototypes => 0, output => 'stdout';
p qx/echo -n Hello/;
output
"Hello"

Related

How to access multiple option values from hash specification

use Getopt::Long;
GetOptions(\%gOptions,
"help",
"size=i",
"filename=s{2}",
);
I am passing options like -
--size 200 --filename abc.txt def.txt
I tried accessing filename from the hash specification through
my #array = $gOptions{filename};
print $array[0];
print $array[1];
However, this is not working. How to access multiple option values from a hash specification %gOptions?
Note :
I can map filename to separate array like this -
"filename=s{2}" => \#filearray,
print "$filearray[1];"
but I am not preferring this method.
The documentation on this form of usage says:
For options that take list or hash values, it is necessary to indicate this by appending an # or % sign after the type
and it will then use a reference to an array or hash in the appropriate field to hold values.
So...
#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
use Getopt::Long;
my %gOptions;
GetOptions(\%gOptions,
"help",
"size=i",
# The # has to come after the type, and before the repeat count.
# Note the single quotes so #{2} isn't subject to variable interpolation
'filename=s#{2}',
);
say for $gOptions{"filename"}->#* if exists $gOptions{"filename"};
# or #{$gOptions{"filename"}} if your perl is too old for postderef syntax
Example:
$ perl foo.pl --filename a b
a
b

Read optional command-line arguments in Perl

I am new to Perl and I'm confused with its handling of optional arguments.
If I have a perl script that's invoked with something along the lines of:
plgrep [-f] < perl regular expression > < file/directory list >
How would I determine whether or not the -f operator is given or not on the command line?
All of the parameters passed to your program appear in the array #ARGV, so you can simply check whether any of the array elements contain the string -f
But if you are writing a program that uses many different options in combination, you may find it simpler to use the Getopt::Long module, which allows you to specify which parameters are optional, which take values, whether there are multiple synonynms for an option etc.
A call to GetOptions allows you to specify the parameters that your program expects, and will remove from #ARGV any that appear in the command line, saving indicators in simple Perl variables that reflect which were provided and what values, if any, they had
For instance, in the simple case that you describe, you could write your code like this
use strict;
use warnings 'all';
use feature 'say';
use Getopt::Long;
use Data::Dump;
say "\nBefore GetOptions";
dd \#ARGV;
GetOptions( f => \my $f_option);
say "\nAfter GetOptions";
dd $f_option;
dd \#ARGV;
output
Before GetOptions
["-f", "regexp", "file"]
After GetOptions
1
["regexp", "file"]
So you can see that before the call to GetOptions, #ARGV contains all of the data in the command line. But afterwards, the -f has been removed and variable $f_option is set to 1 to indicate that the option was specified
Use Getopt::Long. You could, of course, parse #ARGV by hand (which contains command line arguments), but there is no reason to do that with the existence of good modules for the job.
use warnings;
use strict;
use Getopt::Long;
# Set up defaults here if you wish
my ($flag, $integer, $float, $string);
usage(), exit if not GetOptions(
'f|flag!' => \$flag,
'integer:i' => \$integer,
'float:f' => \$float,
'string:s' => \$string
);
# The script now goes. Has the flag been supplied?
if (defined($flag)) { print "Got flag: $flag\n" } # it's 1
else {
# $flag variable is 'undef'
}
sub usage {
print "Usage: $0 [options]\n"; # -f or -flag, etc
}
The $flag can simply be tested for truth as well, if that is sufficient. To only check whether -f is there or not, need just: GetOptions('f' => \$flag); if ($flag) { };.
The module checks whether the invocation specifies arguments as they are expected. These need not be entered, they are "options." However, for an unexpected invocation a die or warn message is printed (and in the above code our usage message is also printed and the script exits). So for script.pl -a the script exits with messages (from module and sub).
Abbreviations of option names are OK, if unambiguous; script.pl -fl 0.5 exits with messages (-flag or -float?) while script.pl -i 5 is OK and $integer is set to 5. On the other hand, if an integer is not supplied after -i that is an error, since that option is defined to take one. Multiple names for options can be specified, like f|flag. Etc. There is far more.

Perl print %hash - need some help to understand this

Every simple Perl code but I don't understand it.
Here we go
#!/usr/bin/env perl
use warnings;
use strict;
my %hash;
$hash{"key"} = "value";
$hash{"key2"} = "value2";
$hash{"key3"} = "value3";
print %hash."\n";
And result is 3/8, remove one kep=>value pair, result is 2/8
If I removed the ."\n" then the result is expected key3value3key2value2keyvalue1
No reason to do this, noticed this accidentlly just try to understand what is happening.
When you append the "\n" to the hash, you force the hash to be interpolated in scalar context, which causes it to print out its current capacity and size. When you remove it, the hash is interpolated in list context, and it prints out its current key/value pairs.
While Mark has covered what's going on here perfectly already, you can get the intended result without forcing the hash into scalar context by using "say %hash;" in versions of perl from 5.10 onwards or so.
You'll need to use feature 'say'; just as you would use warnings; (or to be running under perl -E, which switches on a number of "newer" features)

Using a var to select a var in Perl

I thought you used to be able to do this in "strict" mode, but I may be remembering incorrectly. Is is possible for something like this to work...
use strict;
use warnings;
package SomePackage;
my $TargetPID="demo:5"; #using "our" also works, but not in strict mode
my $VarName="TargetPID";
print ${$VarName}; #works but not in strict or if the var is declared with "my"
exit;
The reason I'm interested is that I'm trying to select a variable based on a text flag in a text file and I'd like to read in the content of the text file into a hash, then substitute some identifier along the lines of "#TargetPID#" with the corresponding variable. Being also able to specify both a package and a variable (or constant) would be a nice tbonus.
I can't think of any advantage of doing it the way you are trying to over just using a hash:
use strict;
use warnings;
package SomePackage;
my %vars = ();
$vars{'TargetPID'}="demo:5";
my $VarName="TargetPID";
print $vars{$VarName};
exit;
If you really must use $TargetPID as a variable and not a member of a hash, you can use eval:
my $TargetPID = "demo:5";
my $VarName = '$TargetPID';
print eval $VarName;
Or, if for some reason you need the value of $VarName to be 'TargetPID' and not '$TargetPID', you can do print eval '$' . $VarName.
You can use the PadWalker module for this. From the documentation:
PadWalker is a module which allows you to inspect (and even change!)
lexical variables in any subroutine which called you. It will only
show those variables which are in scope at the point of the call.
In your case, you would need to use peek_my, which does what it says: it allows you to peek into variables declared by my in a given scope.
#!/usr/bin/perl
use warnings;
use strict;
package SomePackage;
use PadWalker qw/peek_my/;
my $TargetPID = "demo:5";
my $VarName = "TargetPID";
print ${peek_my(0)->{'$' . $VarName}}
The subroutine peek_my takes one argument, a level, which is the number of subroutine calls to go back on the stack. It then returns a hash map of all the lexical my variables that were in scope at the time of the given call. In your case, the variable you want is defined in the same scope as where it is needed, so you would pass in 0, to go back 0 subroutine calls. Then you pull out the data you need like any other hash ref.
Be careful though, from the documentation:
PadWalker is particularly useful for debugging (emphasis mine.) It's even used by
Perl's built-in debugger. (It can also be used for evil, of course.)
I wouldn't recommend using PadWalker directly in production code, but
it's your call. Some of the modules that use PadWalker internally are
certainly safe for and useful in production.

How can I allow undefined options when parsing args with Getopt

If I have a command line like:
my_script.pl -foo -WHATEVER
My script knows about --foo, and I want Getopt to set variable $opt_foo, but I don't know anything about -WHATEVER. How can I tell Getopt to parse out the options that I've told it about, and then get the rest of the arguments in a string variable or a list?
An example:
use strict;
use warnings;
use Getopt::Long;
my $foo;
GetOptions('foo' => \$foo);
print 'remaining options: ', #ARGV;
Then, issuing
perl getopttest.pl -foo -WHATEVER
gives
Unknown option: whatever
remaining options:
You need to configure "pass_through" option via Getopt::Long::Configure("pass_through");
Then it support actual options (e.g. stuff starting with "-" and without the special "--" delimiter to signify the end of "real" options).
Here's perldoc quote:
pass_through (default: disabled)
Options that are unknown, ambiguous or supplied with an invalid option value are passed through in #ARGV instead of being flagged as errors. This makes it possible to write wrapper scripts that process only part of the user supplied command line arguments, and pass the remaining options to some other program.
Here's an example
$ cat my_script.pl
#!/usr/local/bin/perl5.8 -w
use Getopt::Long;
Getopt::Long::Configure("pass_through");
use Data::Dumper;
my %args;
GetOptions(\%args, "foo") or die "GetOption returned 0\n";
print Data::Dumper->Dump([\#ARGV],["ARGV"]);
$ ./my_script.pl -foo -WHATEVER
$ARGV = [
'-WHATEVER'
];
Aren't the remaining (unparsed) values simply left behind in #ARGV? If your extra content starts with dashes, you will need to indicate the end of the options list with a --:
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use Data::Dumper;
my $foo;
my $result = GetOptions ("foo" => \$foo);
print Dumper([ $foo, \#ARGV ]);
Then calling:
my_script.pl --foo -- --WHATEVER
gives:
$VAR1 = [
1,
[
'--WHATEVER'
]
];
PS. In MooseX::Getopt, the "remaining" options from the command line are put into the extra_argv attribute as an arrayref -- so I'd recommend converting!
I think the answer here, sadly though, is "no, there isn't a way to do it exactly like you ask, using Getopt::Long, without parsing #ARGV on your own." Ether has a decent workaround, though. It's a feature as far as most people are concerned that any option-like argument is captured as an error. Normally, you can do
GetOptions('foo' => \$foo)
or die "Whups, got options we don't recognize!";
to capture/prevent odd options from being passed, and then you can correct the user on usage. Alternatively, you can simply pass through and ignore them.