Passing multiple file lists to perl script - perl

I want to pass two file lists to my perl script and have them handled with Getopt::Long for storing an array (via a reference) in a dictionary.
#!/usr/bin/env perl
# author:sb2
use strict;
use warnings;
use Getopt::Long;
use File::Basename;
use Data::Dumper;
print Dumper(#ARGV);
my($config);
$config = &configure(scalar #ARGV);
sub configure{
my $args = shift;
my $config = {};
my #current_samples = ();
#my #old_samples = ();
$config = {'current_samples' => \#current_samples};
#$config = {'old_samples' => \#old_samples};
GetOptions($config,
#"old_samples=s{,}",
"current_samples=s{,}",
"help|h!", )
|| warn "error : $!\n";
print Dumper($config);
return($config);
}
I can happily pass one file list and have it stored as expected:
[sb2 ~]$ perl test.pl -current_samples WS*
$VAR1 = '-current_samples';
$VAR2 = 'WS68726_1401';
$VAR3 = 'WS68726_1402';
$VAR4 = 'WS68726_1500';
$VAR5 = 'WS68726_1501';
$VAR1 = {
'current_samples' => [
'WS68726_1401',
'WS68726_1402',
'WS68726_1500',
'WS68726_1501'
]
};
However, when I uncomment my second list parameter and use that my 'current_samples' variable is now a string with a single filename. Although the 'old_samples' variable has parsed correctly (as above):
[sb2 ~]$ perl test.pl -current_samples WS* -old_samples HG*
$VAR1 = '-current_samples';
$VAR2 = 'WS68726_1401';
$VAR3 = 'WS68726_1402';
$VAR4 = 'WS68726_1500';
$VAR5 = 'WS68726_1501';
$VAR6 = '-old_samples';
$VAR7 = 'HG001';
$VAR8 = 'HG002';
$VAR9 = 'HG003';
$VAR1 = {
'current_samples' => 'WS68726_1501'
'old_samples' => [
'HG001',
'HG002',
'HG003'
]
};
I tried swapping the order of variables around and the only one that made a difference was switching the config assignment ones:
sub configure{
my $args = shift;
my $config = {};
my #current_samples = ();
#my #old_samples = ();
$config = {'current_samples' => \#current_samples};
#$config = {'old_samples' => \#old_samples};
GetOptions($config,
"current_samples=s{,}",
"old_samples=s{,}",
"help|h!", )
|| warn "error : $!\n";
print Dumper($config);
return($config);
}
Produces:
[sb2 ~]$ perl test.pl -current_samples WS* -old_samples HG*
$VAR1 = '-current_samples';
$VAR2 = 'WS68726_1401';
$VAR3 = 'WS68726_1402';
$VAR4 = 'WS68726_1500';
$VAR5 = 'WS68726_1501';
$VAR6 = '-old_samples';
$VAR7 = 'HG001';
$VAR8 = 'HG002';
$VAR9 = 'HG003';
$VAR1 = {
'current_samples' => [
'WS68726_1401',
'WS68726_1402',
'WS68726_1500',
'WS68726_1501'
],
'old_samples' => 'HG003'
};
I can't see anything in the GetOptions CPAN page which alludes to this ordering affect so any help would be greatly appreciated!

From your commented code it looks like you are overwriting $config with these lines:
$config = {'current_samples' => \#current_samples};
#$config = {'old_samples' => \#old_samples};
Instead, do all config assignments in one line:
my $config = {
'current_samples' => \#current_samples,
'old_samples' => \#old_samples,
};
Or you can do them in single lines and assign to the keys of the hashref:
my $config = {};
$config->{'current_samples'} = \#current_samples;
$config->{'old_samples'} = \#old_samples;

As a an alternative solution, Getopt::Declare has syntax to support loading arguments into array references as well:
use strict;
use warnings;
use Getopt::Declare;
my $args = Getopt::Declare->new(
join( "\n",
'[strict]',
"-current-samples <files>... \t List of file names",
"-old-samples <files>... \t List of file names",
)
) || exit(1);
the ... after each tag tells Getopt::Declare to gather arguments into an array reference.
Then you just specify multiple space-separated values on the command line:
perl test-getopt-declare.pl -current-samples a b c d e f -old-samples 1 2 3 4 5 6

Related

Perl - How to add rows in a hash inside a loop?

Iam trying to create a simple array KEY => VALUE from a json response, here's my results when I dump the array but the keys are not what Im excpecting:
$VAR1 = 'expectedvalue1';
$VAR2 = 'expectedvalue2';
$VAR3 = 'expectedvalue3';
and here's my code that I found some part of it here (some comments says that there's backslash missing)
my %result = ();
foreach my $row (#json_response){
$result{ $row->{"json_key"} } = $row->{"json_value"};
}
print Dumper(%result);
While I'm trying to get
expectedkey1 = expectedvalue1
expectedkey2 = expectedvalue2
expectedkey3 = expectedvalue3
Edit : I made a mistake in the names of keys.
Are you trying to get key => value and key/value have the same values?
If you're looking for that, maybe this can help you
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my #array_items = qw(expectedvalue1 expectedvalue2 expectedvalue3);
my %hash_example;
foreach my $value (#array_items) {
push(#{$hash_example{$value}}, $value);
}
print Dumper(\%hash_example);
OUTPUT:
$VAR1 = {
'expectedvalue2' => [
'expectedvalue2'
],
'expectedvalue1' => [
'expectedvalue1'
],
'expectedvalue3' => [
'expectedvalue3'
]
};

No elements found for form number 2 in phantomjs

when I am using "--disk-cache=true" in phantomjs_arg then it's getting error In this line:
my $form = $self->{obj_mech}->form_number( 2 );
No elements found for form number 2 at modules/TestLogin.pm line 1129.
at /usr/local/share/perl/5.22.1/WWW/Mechanize/PhantomJS.pm line 796.
WWW::Mechanize::PhantomJS::signal_condition(WWW::Mechanize::PhantomJS=HASH(0x4cfa120),
"No elements found for form number 2") called at
/usr/local/share/perl/5.22.1/WWW/Mechanize/PhantomJS.pm line 1732
WWW::Mechanize::PhantomJS::xpath(WWW::Mechanize::PhantomJS=HASH(0x4cfa120),
"(//form)[2]", "user_info", "form number 2", "single", 1) called at
/usr/local/share/perl/5.22.1/WWW/Mechanize/PhantomJS.pm line 2102
WWW::Mechanize::PhantomJS::form_number(WWW::Mechanize::PhantomJS=HASH(0x4cfa120),
2) called at modules/TestLogin.pm line 1129
TestLogin::TestLogin_login(TestLogin=HASH(0x4f5c8a8)) called at collectBets.pl line 20 Debugged program terminated. Use q to quit
or R to restart, use o inhibit_exit to avoid stopping after program
termination, h q, h R or h o to get additional info.
without disk-cashe it's working fine.
This is my sample code for better understanding.
#!/usr/bin/perl
use strict;
use warnings;
use Helper;
use WWW::Mechanize::PhantomJS;
use DataBase;
use MyConfig;
use JSON;
use DateTime;
use HTML::Entities;
sub new($$) {
my ($class,$params) = #_;
my $self = $params || {};
bless $self, $class;
$self->{obj_mech} = WWW::Mechanize::PhantomJS -> new( phantomjs_arg => ['--ssl-protocol=any','--disk-cache=true','--max-disk-cache-size=1024'], ignore_ssl_errors => 1);
$self->{obj_helper} = new Helper();
#$self->{obj_db} = new DataBase();
$self->{logged_in} = 0;
#$self->setTorProxy();
#$self->init_market_master();
return $self;
}
Login();
print "\nlogin done...\n";
exit;
sub Login {
my ($self) = #_;
my $html = $self->{obj_mech}->get( "https://www.gmail.com/" );
sleep(25);
$html = $self->{obj_mech}->content;
$self->{obj_mech}->viewport_size({ width => 1366, height => 768 });
my $form = $self->{obj_mech}->form_number( 2 );
my $user_name = '*****';
my $password = '******';
$self->{obj_mech}->set_fields('InputEmail' =>$user_name);
$self->{obj_mech}->set_fields('InputPassword' =>$password);
$self->{obj_mech}->click({ xpath => '//button[#class="PrimaryButton"]' });
sleep(20);
my $test_html=$self->{obj_mech}->content;
$self->{obj_helper}->writeFileNew( "TestLoginPage.html" , $test_html );
my $png = $self->{obj_mech}->content_as_png();
$self->{obj_helper}->writeFileNew( "LoginPage.png" , $png );
return 1;
}
Well, before looking at the disk-cache arguments, I found that there are no such elements.
# There is only 1 form. If you want to keep this line,
# you need to change the form number to 1
my $form = $self->{obj_mech}->form_number( 2 );
# I didn't find input field named 'InputEmail'
# The actual field name is 'Email'
$self->{obj_mech}->set_fields('InputEmail' =>$user_name);
# You have to click 'Next' button firstly then the password
# input box is shown. And the field name should be 'Passwd'
$self->{obj_mech}->set_fields('InputPassword' =>$password);
# The xpath of 'Sign in' button is //input[#value="Sign in"]
$self->{obj_mech}->click({ xpath => '//button[#class="PrimaryButton"]' });
A simple working script either with disk cache or without disk cache:
#! /usr/bin/perl
use strict;
use warnings;
use WWW::Mechanize::PhantomJS;
use open ':std', ':encoding(UTF-8)';
#my $p = WWW::Mechanize::PhantomJS->new(phantomjs_arg=>['--ssl-protocol=any','--disk-cache=false','--max-disk-cache-size=1024'],ignore_ssl_errors=>1);
my $p = WWW::Mechanize::PhantomJS->new(phantomjs_arg=>['--ssl-protocol=any','--disk-cache=true','--max-disk-cache-size=1024'],ignore_ssl_errors=>1);
my $html = $p->get("https://www.gmail.com/");
sleep(5);
write_html('first-page.html', $p->content);
$p->viewport_size({width=>1366,height=>768});
my $form = $p->form_number(1);
my $user_name = '*****';
my $password = '*****';
$p->set_fields('Email'=>$user_name);
sleep(5);
$p->click({xpath=>'//input[#value="Next"]'});
sleep(5);
write_html('after-click-next.html', $p->content);
$p->set_fields('Passwd'=>$password);
sleep(5);
$p->click({xpath=>'//input[#value="Sign in"]'});
sleep(5);
write_html('after-login.html', $p->content);
sub write_html {
my ($file, $content) = #_;
open my $fh, '>', $file or die;
print $fh $content;
close $fh;
}

perl configuration and blocks

I am trying to do the configuration file in perl using
Config::Simple
#!/usr/bin/perl
use Config::Simple;
use Data::Dumper;
use Data::Dump qw(dump);
#$cfg = new Config::Simple('new.conf');
$cfg = new Config::Simple(syntax => 'ini');
$cfg->param("Dialer Onboard.user", "user1");
$cfg->param("Dialer Onboard.pass", "pass1");
$cfg->param("Dialer External.user", "user2");
$cfg->param("Dialer External.pass", "pass2");
$cfg->write("new.conf");
$cfg->read('new.conf');
$user = $cfg->param("Dialer Onboard.user");
print "----" . "$user";
And the new.conf file would be
[Dialer External]
pass=pass2
user=user2
[Dialer Onboard]
pass=pass1
user=user1
For the section or block information, I am using the function get_block() like this
my $config = Config::Simple->new("new.conf")->get_block("Dialer Onboard");
print Dumper $config;
This will give me the output like this
$VAR1 = {
'pass' => 'pass1',
'user' => 'user1'
};
Is there any way to get the only the names of all blocks?
Now I am getting only the number of blocks which is
my $config = Config::Simple->new("new.conf")->get_block();
print Dumper $config;
The output would be
$VAR1 = 2;
You are using get_block() in scalar context; that's why you are getting the number of blocks. Use it in list context to get the names of the blocks.
Try this:
my #config = Config::Simple->new("new.conf")->get_block();
print Dumper \#config;
Output:
$VAR1 = [
'Dialer Onboard',
'Dialer External'
];

perl modifying hash in sub

I'm having trouble understanding how references work with hashes in subs.
In this code, I try to change %config inside the handleOptions() subroutine :
sub handleOption;
my %config = ( gpg => "",
output => "",
pass => "",
host => "",
type => "");
handleOptions(\%config);
print "\n";
print Dumper \%config;
sub handleOptions
{
my ($gpgpath,$type,$pass,$host);
my $pConfig=#_;
GetOptions ("gpg=s" => \$gpgpath,
"type=s" => \$type,
"host=s" => \$type,
"pass=s"=>\$pass);
$pConfig->{'gpg'} = $gpgpath;
$pConfig->{'type'} = $type;
$pConfig->{'pass'} = $pass;
$pConfig->{'host'} = $host;
print Dumper %$pConfig;
}
Here is the output when I give --gpg='/home/daryl/gpg/pass.gpg to the options in cli :
$VAR1 = 'pass';
$VAR2 = undef;
$VAR3 = 'gpg';
$VAR4 = '/home/daryl/gpg/pass.gpg';
$VAR5 = 'type';
$VAR6 = undef;
$VAR7 = 'host';
$VAR8 = undef;
$VAR1 = {
'pass' => '',
'gpg' => '',
'type' => '',
'output' => '',
'host' => ''
};
How should i proceed ?
If you were to use strict and use warnings, you'd see an error message about using a scalar as a hash reference. That would tip you off that the problem is in this line:
my $pConfig=#_;
You're assigning a scalar context of the array #_ to the variable $pConfig. What this means is that $pConfig is storing the number of elements in the array #_.
Instead, you can do:
my ($pConfig) = #_; as KerrekSB suggests, or:
my $pConfig = shift; (which shifts from #_ automatically)
Take a look at perldoc perldata for more information on calling non-scalars in scalar context. Also, unless you're writing a one-liner or a short throw-away script, make sure to always use strict and use warnings.

Unable to pass a hash and a string to a function, together in perl!

I am basically trying to pass a string and a hash to a subroutine in perl.
sub coru_excel {
my(%pushed_hash, $filename) = #_;
print Dumper(%pushed_hash);
}
But it seems data is getting mixed up. The dumped data also includes the $filename. here is the output.
...................
$VAR7 = 'Address';
$VAR8 = [
'223 VIA DE
................
];
$VAR9 = 'data__a.xls' <----- $filename
$VAR10 = undef;
$VAR11 = 'DBA';
$VAR12 = [
'J & L iNC
..................
];
Here is how I called the subroutine.
coru_excel(%hash, "data_".$first."_".$last.".xls");
Arguments are passed to subroutines as one undifferentiated list.
One solution is to reverse the order of the arguments so that the scalar is first.
sub coru_excel {
my($filename, %pushed_hash) = #_;
}
coru_excel("FILE_NAME", %hash);
Another approach is to pass the hash by reference:
sub coru_excel {
my($pushed_hash_ref, $filename) = #_;
}
coru_excel(\%hash, "FILE_NAME");
You could pass the hash as a reference:
sub coru_excel {
my($pushed_hashref, $filename) = #_;
print Dumper(%$pushed_hashref);
}
coru_excel(\%my_hash, $file);
Or you could give special treatment to the final argument before you initialize the hash:
sub coru_excel {
my $filename = pop #_;
my(%pushed_hash) = #_;
print Dumper(%pushed_hash);
}
You have to pass the hash as a reference:
coru_excel(\%hash, "data_".$first."_".$last.".xls");
You use it like this:
sub coru_excel {
my($pushed_hash_ref, $filename) = #_;
my %pushed_hash = %{$pushed_hash_ref};
print Dumper(%pushed_hash); # better: \%pushed_hash or $pushed_hash_ref
}
See perlreftut for a tutorial on references and perlref for further information.
Dumper also produces better usable information when you pass a hash (or array) reference.
See also the related Perl FAQ. From the command line:
perldoc -q pass
or
perldoc -q hash
Refer to perlfaq7: How can I pass/return a {Function, FileHandle, Array, Hash, Method, Regex}?
A small program demonstrating how to do this using reference notation when passing the hash and shift in the subroutine to pull out the parameters.
#!/usr/bin/perl -w
use strict;
sub coru_excel(%$);
my %main_hash = ('key1' => 'val1', 'key2' => 'val2');
my $first = "ABC";
my $last = "xyz";
coru_excel(\%main_hash, "data_" . $first . "_" . $last . ".xls");
exit;
sub coru_excel(%$)
{
my %passed_hash = %{(shift)};
my $passed_string = shift;
print "%passed_hash:\n";
for my $k (keys %passed_hash) {
print " $k => $passed_hash{$k}\n";
}
print "\$passed_string = $passed_string\n";
return;
}