I want to query a list of nickname from a text file.
#!/usr/bin/perl
use strict;
use warnings;
use MongoDB;
# Open file
print "--> Read file\n";
open( INPUT, "<userlist.txt" ) or die "Could not open the file: $!\n";
print "--> Read INPUT OK\n";
open( OUTPUT, ">>outfile.txt" ) or die "Could not open the file: $!\n";
print "--> Read OUTPUT OK\n";
# MongoDB parameter
my $mongoHost = localhost;
my $mongoPort = 12345;
my $conn = MongoDB::Connection->new( "host" => "$mongoHost", "port" => $mongoPort ); # Open connection
my $db = $conn->mylist; # Connect to database
my $user_stats = $db->user_stats; # Choose a collection
print "--> Connect to MongoDB\n";
# Read through line
foreach my $line ( <INPUT> ) {
# Extract content
chomp( $line ); # Remove newline
print "$line\n";
my $statsResult = $user_stats->find( { nickname => '$line' } );
while ( my $obj = $statsResult->next ) {
print $obj->{ "nickname" } . ";";
print $obj->{ "total" } . "\n";
}
}
close( OUTPUT );
close( INPUT );
print "--> End of Code\n";
exit 0;
It seem it fail to recognise variable $line at the line my $statsResult = $user_stats->find( { msisdn => '$line' } );
It works if I replace $line with a string like mynickname. The print statement in previously works ok.
Am I missing something here?
You're using single quotes in your line
my $statsResult = $user_stats->find( { nickname => '$line' } );
Meaning that the database is being searched for the string $line, not the contents of the variable. Remove the single quotes and you should be fine.
Also, here's a nice tutorial on the different forms of quoting in Perl, which explains why single quotes are different from double quotes, what qq means, etc.
Related
I am writing a Perl script which enables the addition and modification of parameters maintained in a particular file.
The script takes the following arguments; Parameter name($paraName), Parameter value($paraVal) and the file ($profile).
The script checks if the parameter($paraName) exists already. if it does, it just changes the value($paraVal) else adds both the parameter($paraName) and the value($paraVal) to the file($profile).
Following is the block of code for the same:
print " checking if parameter is already avaialable";
my $response = system("egrep -qs \"$paraName =\" $profile");
$rc = 1;
if ($response == 0) {
print " Parameter is already available, changing the value now! ";
$rc = system("sed -i 's:.*$paraName.*:$paraName = $paraVal \# Parameter changed by $script:' $profile");
print " Parameter $paraName has been updated with the value $paraVal in the Profile successfully \n\n";
}
else{
print " Parameter is not available, Adding the Paremeter now! ";
$rc = system("echo \"$paraName = $paraVal \# Parameter added by $script\" >> $profile");
print " Parameter $paraName has been added with the value $paraVal in the Profile successfully \n\n";
}
The script works fine for most cases, except when I have arguments with double quotes to be added as a new parameter. It works file for hash(#), slashes (), etc, when passes within a single quote(' ').
This is working in case of changing the value($paraVal) when the parameter($paraName) already exists. But while a new parameter has to be added, this fails to add double quotes in the parameter name.
Would appreciate some help here.
Here is an example of how you could write it as pure Perl:
use feature qw(say);
use strict;
use warnings;
my ( $paraName, $paraVal, $profile ) = #ARGV;
my $script = $0;
open ( my $fh, '<', $profile ) or die "Could not open file '$profile': $!";
my $found = 0;
while( my $line = <$fh> ) {
chomp $line;
if ( my ($key) = $line =~ /^(\Q$paraName\E)\s*=\s*/) {
say "$key = $paraVal \# Parameter changed by $script";
$found = 1;
}
else {
say $line;
}
}
close $fh;
if ( !$found ) {
say "$paraName = $paraVal \# Parameter added by $script";
}
Edit:
The above script does not modify the profile file, but instead writes the modified file to standard output. So it was meant to be used together with Shell redirection to save the output to a new file. To modify the profile file directly, you could use:
use feature qw(say);
use strict;
use warnings;
die "Bad arguments!" if #ARGV != 3;
my ( $paraName, $paraVal, $profile ) = #ARGV;
my $script = $0;
#ARGV = ( $profile );
$^I = '.bak';
my $found = 0;
while (my $line = <<>>) {
chomp $line;
if ( my ($key) = $line =~ /^(\Q$paraName\E)\s*=\s*/) {
say "$key = $paraVal \# Parameter changed by $script";
$found = 1;
}
else {
say $line;
}
} continue {
say "$paraName = $paraVal \# Parameter added by $script" if eof && !$found;
}
This will first save the original profile file to a backup file with .bak extension, and then overwrite the profile file with the modified content.
Try following code as alternative
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Pod::Usage;
use Getopt::Long;
use Data::Dumper;
my %opt; # program options
my %param; # parameters storage
my $fh; # file handle
GetOptions (
'file|f=s' => \$opt{file},
'name|n=s' => \$opt{name},
'value|v=s' => \$opt{value},
'operation|o=s' => \$opt{op},
'help|h' => \$opt{help},
'man|m' => \$opt{man},
'debug|d' => \$opt{debug}
) or pod2usage(1);
pod2usage(1) if $opt{help};
pod2usage(-exitval => 0, -versose => 2) if $opt{man};
pod2usage(1) unless $opt{file};
open $fh, "< $opt{file}"
or die "Couldn't open $opt{file}";
my #lines = <$fh>;
close $fh;
chomp #lines;
print Dumper(\#lines) if $opt{debug};
push #lines, "$opt{name} = $opt{value}"
if $opt{op} eq 'add';
#lines = map { /$opt{name}\s*=/ ? '' : $_ } #lines
if $opt{op} eq 'del';
#lines = map {
s/($opt{name})\s*=\s*(.*)/$1 = $opt{value}/; $_
} #lines if $opt{op} eq 'mod';
map{ say } #lines
if $opt{op} eq 'view';
map {
/$opt{name}\s*=\s*(.*)/ and say 'Verify: '
. ($1 eq $opt{value} ? 'ok' : 'no')
} #lines if $opt{op} eq 'check';
my %save = map { $_ => 1 } qw/add del mod/;
print Dumper(\#lines) if $opt{debug};
if( $save{ $opt{op} } ) {
open $fh, "> $opt{file}"
or die "Couldn't open $opt{file}";
map { say $fh $_ } #lines;
close $fh;
}
__END__
=head1 NAME
program - modify configuration file
=head1 SYNOPSIS
program [options] [file ...]
Usage:
program -op [add|del|mod|view|check] -n param -v value -f file
Options:
--file,-f configuration filename
--name,-n parameter name
--value,-v parameter value
--operation,-o operation to perform
--help,-h brief help message
--man,-m full documentation
--debug,-d debug mode
=head1 OPTIONS
=over 8
=item B<--file,-f>
Configuration file to edit
=item B<--name,-n>
Configuration parameter name to operate on
=item B<--value,-v>
Configuration parameter value to operate on
=item B<--operation,-o>
Operation to perform on parameter: add, del, mod, view, check
=item B<--debug,-d>
Debug flag to print debug messages.
=item B<--help,-h>
Print a brief help message and exits.
=item B<--man,-m>
Prints the manual page and exits.
=back
=head1 DESCRIPTION
B<This program> allows to operate on configuation files variables.
=head1 AUTHOR
B<Polar Bear> L<https://stackoverflow.com/users/12313309/polar-bear>
=cut
I am not getting count of $mapA{$Brand_Name}->{Success} $mapA{$Brand_Name}->{Failure} please help on this actually i raised this problem in another question i.e closed so i am raising in this.
or any other way to increase the count for particular key.
#!/usr/bin/perl
use Text::CSV;
use POSIX qw(strftime);
use Data::Dumper;
use LWP::Simple;
my $APK_GCM="/root/Basavaraj/GCM/cdr_02-01-2018_StreamzGcm.csv";
my $WEB_GCM="/root/Basavaraj/GCM/cdr_02-01-2018_StreamzWebPushNotification.csv";
my $Yesterday= strftime ("%d-%m-%Y", localtime(time-86400));
my $Current_Date= strftime ("%d-%m-%Y",localtime(time));
print "$Yesterday \n";
print "$Current_Date \n";
open(STDOUT, '>', "/root/Basavaraj/STREAMZ_GCM_APK.txt");
#Creating Class to split the document line by line by comma ,
my $csv = Text::CSV->new({ sep_char => ',' });
open (my $data, '<:encoding(utf8)', $APK_GCM) or die "Could Not open File '$APK_GCM' $!\n";
open (my $data1,'<:encoding(utf8)', $WEB_GCM) or die "Could Not open File '$WEB_GCM' $!\n";
my %mapA;
my $dummyA =<$data>;
while (my $line = <$data>) {
if ($csv->parse($line)) {
my #fields = $csv->fields();
my $Brand_Name=$fields[2];
my $Streamz_Sent=$fields[5];
my $GoogleResA=$fields[5];
$mapA{$Brand_Name} = {Success =>0,Failure=> 0} unless exists ($mapA{$Brand_Name});
my $failureA='{error:MismatchSenderId}';
if ($GoogleResA eq $failureA){
$mapA{$Brand_Name}->{Failure}++;
print "$Brand_Name:$mapA{$Brand_Name}->{Failure} \n";
}else{
$mapA{$Brand_Name}->{Success}++;
print "$Brand_Name:$mapA{$Brand_Name}->{Success} \n";
}
} else {
warn "Line could not be parsed: $line\n";
}
}
#$, = ",";
print " $mapA{$Brand_Name}->{Failure} \n";
my $KeyA;
while (($keyA)=each (%mapA)){
my $success= $mapA{$Brand_Name}->{Success};
my $failure= $mapA{$Brand_Name}->{Failure};
print "$keyA $mapA{$Brand_Name}->{Failure}++ $mapA{$Brand_Name}->{Success}++ \n";
}
foreach my $name ( keys %mapA) {
print " $mapA{$Brand_Name}->{Failure} \n";
print " $mapA{$Brand_Name}->{Success} \n";
print "$name $mapA{$Brand_Name}->{Success} $mapA{$Brand_Name}->{Failure} \n";
}
Code looks messy and not clear, but i'm posting here the way to increment the count for this case, hope it will help someway, copy and paste the below program in your machine and try it out(demonstrates how to increment count, very similar to scenario mentioned above)
#!/usr/bin/perl
use strict;
use warnings;
my %results;
%results = ('Brand A' => {'Success' => 0, 'Failure' => 0},
'Brand B' => {'Success' => 1, 'Failure' => 1});
# add new entry into existing hash
#
$results{'Brand C'}{'Success'} = 5;
$results{'Brand C'}{'Failure'} = 6;
# increment Success count for specific brand straightaway
$results{'Brand B'}{'Success'}++;
print "Success count for brand B = $results{'Brand B'}{'Success'}\n";
#print out hash
#
# first key for example Brand A
for my $brand (keys %results)
{
print "Printing brand here: $brand-->";
# next key for example 'Success' or 'Failure'
#
for my $result (keys %{$results{$brand}})
{
#increment success or failure count
$results{$brand}{$result}++;
print "$result-->$results{$brand}{$result},";
}
print "\n";
}
I need to search for a particular string in a file and then assign it to a variable, example: in the file content it is written as CURRENT_RUN_ID=1636, so I need to search for string CURRENT_RUN_ID and assign its given value i.e. 1636 toa variable sayrunvar`, for this I tried below given, but it doesn't seem to be working, can you correct me here?
opendir(DAPATH,$sDAPATH) or die "Can't open $sDAPATH: $!";
print OUTLOG "\nfound da path : $sDAPATH\n";
my #adirs = readdir(DAPATH);
print OUTLOG "Starting capturing DA\n";
my $da = glob "*$runVar.csv*";
print OUTLOG "Assigned DA";
closedir(DAPATH);
}
It is not matching because you are giving spaces at if (/CURRENT_RUN_ID = \s*(.*)/) in the match.It is searching for spaces in the string.
The pattern what you are trying to match will match CURRENT_RUN_ID = 1636 string, notice the spaces between CURRENT_RUN_ID and = and after =. If there is match then the no of spaces in the pattern should be exactly same as the no of spaces in the string.
There is space between CURRENT_RUN_ID and = and also after =.
Better remove the faulty spaces and make the space optional using \s* try this:
if (/CURRENT_RUN_ID\s*=\s*(.*)/){
my $runvar = $1;
print "$runvar \n";
}
EDIT:
As per your requirement I changed your script as(I am not writing to file):
#!/usr/bin/perl
use strict;
use warnings;
open my $fh, '<', 'file' or die "unable to open file : $! \n";
my $runVar="";
while(<$fh>){
if (/CURRENT_RUN_ID\s*=\s*(.*)/){
print "we can now assign run id\n";
$runVar = $1;
print "assigned current run id to variable\n";
}
else {
print "run id not assigned\n";
}
}
close($fh);
Here you are not matching any of the lines while performing the pattern matching in line 18. And even you can reduce few repetitive steps in the code.
But for your convenience I have used your program.
#!C:\Strawberry\perl\bin
use strict;
use warnings;
my $sSuccessString = "CURRENT_RUN_ID";
open(LOG,"$slogfile") or die("Can't open $slogfile\n");
my $sLines;
{
local $/ = undef;
$sLines=<LOG>;
}
if($sLines =~ m/$sSuccessString/){
open(OUTLOG, ">>test.txt");
print OUTLOG "found current run id in log\n";
print OUTLOG "it is found in log as : $sSuccessString \n";
#if ($sLines =~ m/(CURRENT_RUN_ID=.*)/i) {
#print OUTLOG "<p>" . $1 . "<\/p>\n";
#In below line you need to match the pattern with the line.
if ($sLines=~/CURRENT_RUN_ID=(.*)/){
print OUTLOG "we can now assign run id\n";
my $runVar = $1;
print "$runVar\n";
print OUTLOG "assigned current run id to variable\n";
}
else {
print "run id not assigned\n";
}
}
I have copied your log file content to one of my text file (prog.txt) on my desktop and ran the script. Please see the output.
#!C:\Strawberry\perl\bin
use strict;
use warnings;
my $sSuccessString = "CURRENT_RUN_ID";
open(LOG,"Prog.txt") or die("Can't open text file\n");
my $sLines;
{
local $/ = undef;
$sLines=<LOG>;
}
if($sLines =~ m/$sSuccessString/){
open(OUTLOG, ">>test.txt");
print OUTLOG "found current run id in log\n";
print OUTLOG "it is found in log as : $sSuccessString \n";
#if ($sLines =~ m/(CURRENT_RUN_ID=.*)/i) {
#print OUTLOG "<p>" . $1 . "<\/p>\n";
if ($sLines=~/CURRENT_RUN_ID=(.*)/){
print OUTLOG "we can now assign run id\n";
my $runVar = $1;
print "$runVar\n";
print OUTLOG "assigned current run id to variable\n";
}
else {
print "run id not assigned\n";
}
}
OUTPUT:
C:\Users\hclabv\Desktop>perl run1.pl
1637
And my log file (test.txt) where we are capturing the logs while running script is as below.
found current run id in log
it is found in log as : CURRENT_RUN_ID
we can now assign run id
assigned current run id to variable
For getting runVar.csv file from desired directory, I have added the below piece of code with in the if loop
opendir(DAPATH,"C:/Users/hclabv/Desktop/Scripting/files") or die "Can't open DAPATH: $!";
print OUTLOG "\nfound da path : DAPATH\n";
my #adirs = readdir(DAPATH);
print "csv files #adirs\n";
print OUTLOG "Starting capturing DA\n";
my $csvfile = "$runVar.csv";
foreach my $adirs (#adirs) {
if ($adirs eq $csvfile) {
print "file found\n";
my $da = $adirs;
print "csv file is $da\n";
}
print OUTLOG "Assigned DA";
close(DAPATH);
}
I'm trying to populate the grep result to csv file. But it is showing the following error.
"Use of uninitialized value in concatenation (.) or string at"
code:
sub gen_csv {
my $db_ptr = shift #_;
my $cvs_file_name = shift #_;
open( FILE, ">$cvs_file_name" ) or die("Unable to open CSV FILE $cvs_file_name\n");
print FILE "Channel no, Page no, \n";
foreach my $s ( #{$db_ptr} ) {
my $tmp = "$s->{'ch_no'},";
$tmp .= "$s->{'pg_no'},";
print FILE $tmp;
}
close(FILE);
}
sub parse_test_logs {
my $chnl;
my $page;
my $log = "sample.log";
open my $log_fh, "<", $log;
while ( my $line = <$log_fh> ) {
if ( $line =~ /(.*):.*solo_(.*): queueing.*/ ) {
my $chnl = $1;
my $page = $2;
}
my %test_details = (
'ch_no' => $chnl,
'pg_no' => $page, # <- was missing closing single quote
);
push( #{$dba_ptr}, \%test_details );
}
close log_fh;
}
Any suggestions on what i'm missing out?
(i'm getting the above error pointing to my $tmp = "$s->{'ch_no'},"; in gen_csv module)
Most likely this is due to NULL values in your DB records or the keys you are using are wrong. Either way, the warning is because the ch_no value does not exist.
If you don't care about NULL values, and you are fine with some of the values being missing, then you can suppress warnings for uninitialized values.
no warnings 'uninitialized';
Your problem involves this block:
if ( $line =~ /(.*):.*solo_(.*): queueing.*/ ) {
my $chnl = $1;
my $page = $2;
}
my %test_details = (
'ch_no' => $chnl,
'pg_no' => $page,
);
You're capturing your variables, but you have them declared with my within the if block. Those lexicals then go out of scope and are undef when used to initialize the hash.
I recommend simplifying your parsing function to the following:
sub parse_test_logs {
my $log = "sample.log";
open my $log_fh, "<", $log;
while (<$log_fh>) {
if ( my ( $chnl, $page ) = /(.*):.*solo_(.*): queueing.*/ ) {
push #{$dba_ptr}, { 'ch_no' => $chnl, 'pg_no' => $page };
} else {
warn "regex did not match for line $.: $_";
}
}
close $log_fh;
}
Finally, it's possible that you already are, but I just want to pass on the ever necessary advice to always include use strict; and use warnings; at the top of EVERY Perl script.
I am having an input file like this:
Input file
I need to replace the value #pSBSB_ID="*" of #rectype=#pRECTYPE="SBSB" with #pMEME_SSN="034184233", value of #pRECTYPE="SMSR", ..and have to delete the row where #rectype='#pRECTYPE="SMSR", '
Example:
So, after changes have been made, the file should be like this:
....#pRECTYPE="SBSB", #pGWID="17199269", #pINPUT_METHOD="E", #pGS08="005010X220A1", #pSBSB_FAM_UPDATE_CD="UP", #pSBSB_ID="034184233".....
....#pRECTYPE="SBEL", #pSBEL_EFF_DT="01/01/2013", #pSBEL_UPDATE_CD="TM", #pCSPD_CAT="M", #pCSPI_ID="MHMO1003"
.
.
.
Update
I tried below mentioned code:
Input file extension: mms and there are multiple files to process.
my $save_for_later;
my $record;
my #KwdFiles;
my $r;
my $FilePath = $ARGV[0];
chdir($FilePath);
#KwdFiles = <*>;
foreach $File(#KwdFiles)
{
unless(substr($File,length($File)-4,length($File)) eq '.mms')
{
next;
}
unless(open(INFILE, "$File"))
{
print "Unable to open file: $File";
exit(0);
}
print "Successfully opened the file: \"$File\" for processing\n\n";
while ( my $record = <INFILE> ) {
my %r = $record =~ /\#(\w+) = '(.*?)'/xg;
if ($r{rectype} eq "SMSR") {
$save_for_later = $r{pMEME_SSN};
next;
}
elsif ($r{rectype} eq "SBSB" and $r{pSBSB_ID} eq "*") {
$record =~ s|(\#pSBSB_ID = )'.*?'|$1'$save_for_later'|x;
}
close(INFILE);
}
}
But, I am still not getting the updated values in the file.
#!/usr/bin/perl
open IN, "< in.txt";
open OUT, "> out.txt";
my $CUR_RECID = 1^1;
while (<IN>) {
if ($CUR_RECID) {
s/recname='.+?'/recname='$CUR_RECID'/ if /rectype='DEF'/;
$CUR_RECID = 1^1;
print OUT;
}
$CUR_RECID = $1 if /rectype='ABC'.+?rec_id='(.+?)'/;
}
close OUT;
close IN;
Try that whole code. No need a separate function; This code does everything.
Run this script from your terminal with the files to be modified as arguments:
use strict;
use warnings;
$^I = '.bak'; #modify original file and create a backup of the old ones with .bak appended to the name
my $replacement;
while (<>) {
$replacement = $1 if m/(?<=\#pMEME_SSN=)("\d+")/; #assume replacement will be on the first line of every file.
next if m/^\s*\#pRECTYPE="SMSR"/;
s/(?<=\#pSBSB_ID=)("\*")/$replacement/g;
print;
}