i had script:
# N1089767N_7_SWOPT_03-Jul-2011_78919186.xml
# N1089767N_7_SWOPT_25-Jun-2011_72745892.xml
# N1089772L_9_SWOPT_03-Jul-2011_78979055.xml
# N1089772L_9_SWOPT_20-Jul-2011_69380887.xml
# N1089772L_9_SWOPT_29-Jun-2011_74754662.xml
open( CONSULTS, "confile" );
#scons = <CONSULTS>;
close CONSULTS;
my %is_trade_id_unique;
foreach ( reverse sort consort #scons ) {
chomp;
#print $_. "\n";
if ( $_ =~ m/(\w+_\d+_\w+)_(\d+)-([A-Za-z]{3})-2011_(\d+)[.]xml/i ) {
my ( $trade_id, $date, $month, $row_num ) = ( $1, $2, $3, $4 );
if ( !$is_trade_id_unique{$trade_id} ) {
print $_. "\n";
$is_trade_id_unique{$trade_id} = 1;
}
#print $_."\n";
}
}
#N1089767N_7_SWOPT_03-Jul-2011_78919186.xml
sub consort {
$aa = $a;
$bb = $b;
# save our variables because our sort routine affects them. If I "chomp $a"
# that will actually change the line seen in the foreach loop that calls this.
chomp $aa;
chomp $bb;
$aa =~ s/^ *//;
$bb =~ s/^ *//;
my %months = (
FY => 0,
Jan => 1,
Feb => 2,
Mar => 3,
Apr => 4,
May => 5,
Jun => 6,
Jul => 7,
Aug => 8,
Sep => 9,
Oct => 10,
Nov => 11,
Dec => 12,
);
my ( $trade_id, $date, $month, $row_num );
my ( $btrade_id, $bdate, $bmonth, $brow_num );
if ( $aa =~ m/(\w+_\d+_\w+)_(\d+)-([A-Za-z]{3})-2011_(\d+)[.]xml/i ) {
( $trade_id, $date, $month, $row_num ) = ( $1, $2, $months{$3}, $4 );
}
if ( $bb =~ m/(\w+_\d+_\w+)_(\d+)-([A-Za-z]{3})-2011_(\d+)[.]xml/i ) {
( $btrade_id, $bdate, $bmonth, $brow_num ) =
( $1, $2, $months{$3}, $4 );
}
$trade_id cmp $btrade_id
|| $month <=> $bmonth
|| $date <=> $bdate
|| $row_num <=> $brow_num;
}
and i rwrite this script to
#!/usr/bin/perl
use strict;
use warnings;
#use Smart::Comments;
use constant RegExp_parse_name => qr/(\w+)_(\d{2})-(\w{3})-(\d{4})_(\d+)/;
#qr/([A-Z0-9]+_\d+_[A-Z0-9]+)_(\d+)-([A-Z][a-z]{2})-(20\d{2})_(\d+)[.]xml/;
#create month hash
my #month = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/;
my %months;
foreach my $index ( 0 .. $#month ) { $months{ $month[$index] } = $index }
#generate tmp array for special sort
my #tmp_scons;
while ( my $str = <DATA> ) {
chomp($str);
my ( $trade_id, $date, $month, $year, $row_num ) =
$str =~ RegExp_parse_name;
$trade_id or next;
$month = $months{$month};
push #tmp_scons, [ "$trade_id:$year-$month-$date:$row_num", $str ];
}
my #scons = map $_->[1], sort { $a cmp $b } #tmp_scons;
### #tmp_scons:#tmp_scons
### #scons:#scons
### %months:%months
my %is;
foreach my $str (#scons) {
my ( $trade_id, $date, $month, $year, $row_num ) =
$str =~ RegExp_parse_name;
if ( !$is{$trade_id} ) {
print "$str\n";
}
$is{$trade_id}++;
#print "$str\n";
}
__DATA__
N1089767N_7_SWOPT_03-Jul-2011_78919186.xml
N1089767N_7_SWOPT_25-Jun-2011_72745892.xml
N1089772L_9_SWOPT_03-Jul-2011_78979055.xml
N1089772L_9_SWOPT_20-Jul-2011_69380887.xml
N1089772L_9_SWOPT_29-Jun-2011_74754662.xml
but it doesn't sort correctly what the matter?
In this line:
my #scons = map $_->[1], sort { $a cmp $b } #tmp_scons;
You are sorting the transformed data, and then pulling out the origional. However, in your sort block, when you write $a cmp $b you are comparing the array references, so perl is doing something like 'ARRAY(0x123412)' cmp 'ARRAY(0x234234)' rather than looking at your transformed data, which is in the first element of that array.
Rewrite the line as follows:
my #scons = map $_->[1], sort { $a->[0] cmp $b->[0] } #tmp_scons;
And you will be correctly sorting on the transformed value.
#as a result
#!/usr/bin/env perl
######################################
# $URL: http://mishin.narod.ru $
# $Date: 2011-09-14 19:53:20 +0300 (Web, 14 Sep 2011) $
# $Author: mishin nikolay $
# $Revision: 1.02 $
# $Source: get_latest.pl $
# $Description: Sort trades and get latest $
##############################################################################
use strict;
use warnings;
use utf8;
use Data::Dumper;
use Carp;
use English qw(-no_match_vars);
our $VERSION = '0.01';
my $RGX_SHORT_MESS = qr/^(\w+)_(\d{2})-(\w{3})-(\d{4})_(\d+)/smo;
my $RGX_LONG_MESS = qr/^message[.](\w+)[.](\w+)_(\d{2})-(\w{3})-(\d{4})/smo;
#create month hash
my %months;
# two symbol for correct literal matching
#months{qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec )} =
( '00' .. '11' );
my ( $result, $index );
my $file = shift; #'file_names.txt';
open my $fh, q{<}, $file or croak "unable to open:$file $ERRNO";
process_data($fh); #my #file_names = <$fh>;
close $fh or croak "unable to close: $file $ERRNO";
sub process_data {
my ($fh) = #_;
while ( my $str = <$fh> ) {
chomp $str;
my $search_str = $str;
my $trade_id;
if ( $search_str =~ s/$RGX_SHORT_MESS/$4-$months{$3}-$2:$5/sm ) {
$trade_id = $1;
}
elsif ( $search_str =~ s/$RGX_LONG_MESS/$5-$months{$4}-$3:$1/sm ) {
$trade_id = $2;
}
else { next }
# so, from now we are search BIGGEST value & ignore less
next
if ( exists $index->{$trade_id}
&& ( $index->{$trade_id} gt $search_str ) );
$index->{$trade_id} = $search_str;
$result->{$trade_id} = $str;
}
# $result
foreach ( reverse sort keys %{$result} ) {
print $result->{$_} . "\n";
}
return;
}
__DATA__
N1089767N_7_SWOPT_03-Jul-2011_78919186.xml
N1089767N_7_SWOPT_25-Jun-2011_72745892.xml
N1089772L_9_SWOPT_03-Jul-2011_78979055.xml
N1089772L_9_SWOPT_20-Jul-2011_69380887.xml
N1089772L_9_SWOPT_29-Jun-2011_74754662.xml
message.110530033311A4259348AS26.A4259348AS_26_SWOPT_01-Jul-2011.xml
message.110530033311A4259348AS26.A4259348AS_26_SWOPT_31-May-2011.xml
A4259348AS_26_SWOPT_29-Jun-2011_74754662.xml
Related
I have a file with following contents:
TIME
DATE TIME DAY
191227 055526 FRI
RC DEV SERVER
RC1 SERVER1
RC2 SERVER2
RC3 SERVER3
END
I am fetching argument values from this file, say if I pass DATE as an argument to the script I am getting corresponding value of the DATE. i.e., 191227
When I pass multiple arguments say DATE, DAY I should get values:
DATE=191227
DAY=FRI
But what I am getting here is:
DATE=191227
DAY=NULL
And if I pass RC as an argument I should get:
RC=RC1,RC2,RC3
The script looks below:
#!/usr/bin/perl
use strict;
use Data::Dumper;
print Dumper(\#ARGV);
foreach my $name(#ARGV){
print "NAME:$name\n";
my ($result, $start, $stop, $width) = "";
while(my $head = <STDIN>)
{
if( $head =~ (m/\b$name\b/g))
{
$start = (pos $head) - length($name);
$stop = (pos $head);
my $line = <STDIN>;
pos $head = $stop+1;
$head =~ (m/\b/g);
$width = (pos $head) - $start;
$result = substr($line,$start,$width);
}
}
$result =~ s/^\s*(.*?)\s*$/$1/;
print "$name=";
$result = "NULL" if ( $result eq "" );
print "$result\n";
}
Can someone please help me to get values if I pass multiple arguments also if suppose argument value have data in multiple lines it should be printed comma separated values (ex: for RC, RC=RC1,RC2,RC3).
Here is an example, assuming the input file is named file.txt and the values are starting at the same horizontal position as the keys:
package Main;
use feature qw(say);
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my $self = Main->new(fn => 'file.txt', params => [#ARGV]);
$self->read_file();
$self->print_values();
sub read_file {
my ( $self ) = #_;
my $fn = $self->{fn};
open ( my $fh, '<', $fn ) or die "Could not open file '$fn': $!";
local $/ = ""; #Paragraph mode
my #blocks = <$fh>;
close $fh;
$self->{values} = {};
for my $block (#blocks) {
$self->parse_block( $block );
}
}
sub parse_block {
my ( $self, $block ) = #_;
my #lines = split /\n/, $block;
my $header = shift #lines;
my ($keys, $startpos) = $self->get_block_keys( $header );
for my $line ( #lines ) {
for my $key (#$keys) {
my $startpos = $startpos->{$key};
my $str = substr $line, $startpos;
my ( $value ) = $str =~ /^(\S+)/;
if ( defined $value ) {
push #{$self->{values}{$key}}, $value;
}
}
}
}
sub get_block_keys {
my ( $self, $header ) = #_;
my $values = $self->{values};
my #keys;
my %spos;
while ($header =~ /(\S+)/g) {
my $key = $1;
my $startpos = $-[1];
$spos{$key} = $startpos;
push #keys, $key;
}
for my $key (#keys) {
if ( !(exists $values->{$key}) ) {
$values->{$key} = [];
}
}
return (\#keys, \%spos);
}
sub new {
my ( $class, %args ) = #_;
return bless \%args, $class;
}
sub print_values {
my ( $self ) = #_;
my $values = $self->{values};
for my $key (#{$self->{params}}) {
my $value = "<NO VALUE FOUND>";
if ( exists $values->{$key} ) {
$value = join ",", #{$values->{$key}};
}
say "$key=$value";
}
}
Edit
If you want to read the file from STDIN instead, change the following part of the code:
# [...]
my $self = Main->new(params => [#ARGV]);
$self->read_file();
$self->print_values();
sub read_file {
my ( $self ) = #_;
local $/ = ""; #Paragraph mode
my #blocks = <STDIN>;
$self->{values} = {};
for my $block (#blocks) {
$self->parse_block( $block );
}
}
# [...]
I'm having problems intercepting the contents of the lines above what I'm reading $lines[0] as following foreach loop
my $IN_DIR = "/tmp/appo/log"; # Input Directories
my $jumprow = '<number of row to skip>'; # This is a value
foreach my $INPUT ( glob( "$IN_DIR/logrotate_*.log" ) ) {
open( my $fh, '<', $INPUT ) or die $!;
while ( <$fh> ) {
next unless $. > $jumprow;
my #lines = split /\n/;
my $i = 0;
foreach my $lines ( #lines ) {
if ( $lines[$i] =~ m/\A#\d.\d.+#\d{4}\s\d{2}\s\d{2}\s\d{2}:\d{2}:\d{2}:\d{3}#\+\d+#\w+#\/\w+\/\w+\/Authentication/ ) {
# Shows only LOGIN/LOGOUT access type and exclude GUEST users
if ( $lines[ $i + 2 ] =~ m/Login/ || $lines[ $i + 2 ] =~ m/Logout/ && $lines[ $i + 3 ] !~ m/Guest/ ) {
my ( $y, $m, $d, $time ) = $lines[$i] =~ /\A#\d.\d.+#(\d{4})\s(\d{2})\s(\d{2})\s(\d{2}:\d{2}:\d{2}:\d{3})/;
my ( $action ) = $lines[ $i + 2 ] =~ /\A(\w+)/;
my ( $user ) = $lines[ $i + 3 ] =~ /\w+:\s(.+)/;
print "$y/$m/$d;$time;$action;$user\n";
}
}
else {
next; # Is this next technically necessary according to you?
}
$i++;
}
}
close( $fh );
}
The Tie::File
module could help me
my $IN_DIR = "/tmp/appo/log"; # Input Directories
my $jumprow = '<number of row to skip>'; # This is a value
foreach my $INPUT ( glob( "$IN_DIR/logrotate_*.log" ) ) {
tie #lines, 'Tie::File', $INPUT, mode => O_RDONLY;
or die $!;
my $i = $.;
next unless $i > $jumprow;
foreach my $lines ( #lines ) {
if ( $lines[$i] =~ m/\A#\d.\d.+#\d{4}\s\d{2}\s\d{2}\s\d{2}:\d{2}:\d{2}:\d{3}#\+\d+#\w+#\/\w+\/\w+\/Authentication/ ) {
# Shows only LOGIN/LOGOUT access type and exclude GUEST users
if ( $lines[ $i + 2 ] =~ m/Login/ || $lines[ $i + 2 ] =~ m/Logout/ && $lines[ $i + 3 ] !~ m/Guest/ ) {
my ( $y, $m, $d, $time ) = $lines[$i] =~ /\A#\d.\d.+#(\d{4})\s(\d{2})\s(\d{2})\s(\d{2}:\d{2}:\d{2}:\d{3})/;
my ( $action ) = $lines[ $i + 2 ] =~ /\A(\w+)/;
my ( $user ) = $lines[ $i + 3 ] =~ /\w+:\s(.+)/;
print "$y/$m/$d;$time;$action;$user\n";
}
}
else {
next; # Is this next technically necessary according to you?
}
$i++;
}
}
Could you tell me if my declaration with Tie::File is correct or not?
This is only a part of my master script as indicated in following guide mcve
Actually without tie, my master scripts works only with $lines[0], it doesn't take value from $lines[$i+2] or $lines[$i+3]
It looks like you're getting very lost here. I've written a working program that processes the data you showed in your previous question; it should at least form a stable basis for you to continue your work. I think it's fairly straightforward, but ask if there's anything that's not obvious in the Perl documentation
use strict;
use warnings 'all';
use feature 'say';
use autodie; # Handle IO failures automatically
use constant IN_DIR => '/tmp/appo/log';
chdir IN_DIR; # Change to input directory
# Status handled by autodie
for my $file ( glob 'logrotate_*.log' ) {
say $file;
say '-' x length $file;
say "";
open my $fh, '<', $file; # Status handled by autodie
local $/ = ""; # Enable block mode
while ( <$fh> ) {
my #lines = split /\n/;
next unless $lines[0] =~ /
^
\# \d.\d .+?
\# (\d\d\d\d) \s (\d\d) \s (\d\d)
\s
( \d\d : \d\d : \d\d : \d\d\d )
/x;
my ( $y, $m, $d, $time ) = ($1, $2, $3, $4);
$time =~ s/.*\K:/./; # Change decimal point to dot for seconds
next unless $lines[2] =~ /^(Log(?:in|out))/;
my $action = $1;
next unless $lines[3] =~ /^User:\s+(.*\S)/ and $1 ne 'Guest';
my $user = $1;
print "$y/$m/$d;$time;$action;$user\n";
}
say "";
}
output
logrotate_0.0.log
-----------------
2018/05/24;11:05:04.011;Login;USER4
2018/05/24;11:04:59.410;Login;USER4
2018/05/24;11:05:07.100;Logout;USER3
2018/05/24;11:07:21.314;Login;USER2
2018/05/24;11:07:21.314;Login;USER2
2018/05/26;10:48:02.458;Logout;USER2
2018/05/28;10:00:25.000;Logout;USER0
logrotate_1.0.log
-----------------
2018/05/29;10:09:45.969;Login;USER4
2018/05/29;11:51:06.541;Login;USER1
2018/05/30;11:54:03.906;Login;USER4
2018/05/30;11:59:59.156;Logout;USER3
2018/05/30;08:32:11.348;Login;USER4
2018/05/30;11:09:54.978;Login;USER2
2018/06/01;08:11:30.008;Logout;USER2
2018/06/01;11:11:29.658;Logout;USER1
2018/06/02;12:05:00.465;Logout;USER9
2018/06/02;12:50:00.065;Login;USER9
2018/05/24;10:43:38.683;Login;USER1
I want to write perl code to concatenate value of a column2 if other column value1 is same. My input is tab delimited and contains 3 cloumns.
Input file:
Date Server application
01/02/2013 00:00 abc123 perl_module_1
01/02/2013 00:00 abc123 oracle_patch_201
03/05/2014 00:00 abc123 Microsoft_patch_71
04/04/2015 00:00 xyz1 oracle_patch_201
02/12/2015 00:00 xyz1 Cygwin_app
Output:
abc123 = ("perl_module_1","oracle_patch_201","Microsoft_patch_71")
xyz1 = ("oracle_patch_201","Cygwin_app")
My code is as below. As you can see it is not good enough
#!usr/bin/perl
use strict;
use warnings;
my $file = 'oneplatformserver.txt';
open my $info, $file or die "could not open $file: $!";
my $application_string="";
my $date_string="";
while (my $line= <$info>)
{
chomp $line;
my #values = split('\t', $line);
my $application= $values[2];
# $application =~ s/^\s+|\s+$//g; # This command will trim spaces at the end of the line
my $Quoteapplication = '"'.$application.'"';
my $QuoteDate = '"'.$oracledate.'"';
$application_string = join(',',$application_string,$Quoteapplication);
$date_string = join(',',$date_string,$QuoteDate);
print "Date_String is $date_string \n";
printf("UPA \"TSTCM2:%s.A;1\" /ATTRIBUTES=(application_ID=[ %s ],APPLIED_DATE=[ %s ])", $server,$application_string,$date_string);
}
close $info;
# printf("UPB \"QAS:%s.A;1\" /ATTRIBUTES=(application_ID=[ %s ],APPLIED_DATE=[ %s ])", $server,$applicationstring,$datestring);
As you are talking about key value pairs, the answer is 'use a hash'.
my %applications_on;
while ( <$info> ) {
chomp;
my ( $date, $time, $server, $application ) = split;
push ( #{ $applications_on{$server} }, $application );
}
foreach my $server ( keys %applications_on ) {
print "($server) = ".join ( ",", #{ $applications_on{$server} } );
}
Something like that, at any rate.
use strict;
use warnings;
use 5.016;
use Data::Dumper;
my $fname = 'data.txt';
open my $INFILE, '<', $fname
or die "Couldn't open $fname: $!";
my $header = <$INFILE>;
say "0123456789" x 7;
say $header;
my %apps_for;
while (my $line = <$INFILE>) {
my ($server, $app) = unpack '#21 A14 A*', $line; #see explanation below
my $trailing_whitespace = qr{\s* \z}xms;
$server =~ s/$trailing_whitespace//;
$app =~ s/$trailing_whitespace//;
push #{$apps_for{$server}}, $app;
}
close $INFILE;
say Dumper(\%apps_for);
for my $server (keys %apps_for) {
say "$server:";
say " $_" for #{$apps_for{$server}};
}
--output:--
0123456789012345678901234567890123456789012345678901234567890123456789
Date Server application
$VAR1 = {
'xyz1' => [
'oracle_patch_201',
'Cygwin_app'
],
'abc123' => [
'perl_module_1',
'oracle_patch_201',
'Microsoft_patch_71'
]
};
xyz1:
oracle_patch_201
Cygwin_app
abc123:
perl_module_1
oracle_patch_201
Microsoft_patch_71
...
#21 A14 A* #21 -> move to position 21
A14 -> extract 14 characters(A)
A* -> extract the remaining(*) characters(A)
If you really want the exact output you showed:
for my $server (keys %apps_for) {
local $" = ', ';
say "$server = (#{$apps_for{$server}})";
}
--output:--
xyz1 = (oracle_patch_201, Cygwin_app)
abc123 = (perl_module_1, oracle_patch_201, Microsoft_patch_71)
$"
When an array or an array slice is interpolated into a double-quoted
string or a similar context such as /.../ , its elements are separated
by this value. Default is a space.
http://perldoc.perl.org/perlvar.html
This program gets numeric values from the web for each of the values in my #values array
I want these values to be printed out in a table which looks like
il9 il8 il7
2012 v1 b1
2011 v2 b2
2010 v3 b3
.
.
2000 v12 b12
where v1 .. v12 are values for the first variable in #values etc. here is my program please help me structure it. Is there an escape character that could take me back to the first line of the program in perl
thanks
#!/usr/bin/perl -w
use strict;
use LWP::UserAgent;
use URI;
my $browser = LWP::UserAgent->new;
$browser->timeout(10);
$browser->env_proxy;
open(OUT, ">out");
my $i = 2013;
while ($i-- > 2000){print OUT "$i\n"}
my $a = 2013 ;
my $base = 'http://webtools.mf.uni-lj.si/public/summarisenumbers.php';
my #values = ('il9', 'il8', 'il6' );
foreach my $value (#values) {
print OUT "$value \n"
while ($a-- > 2000){
my $b = $a + 1;
my $c = $b + 1;
my $query = '?query=('.$value.')'.$a.'[dp] NOT '.$b.'[dp] NOT '.$c.'[dp]';
my $add = $base.$query;
#my $url = URI->new($add);
#my $response = $browser->get($url);
#if($response->is_success) {print OUT $response->decoded_content;}
#else {die $response->status_line};
print OUT "$query\n";
} $a = 2013; print OUT
}
close(OUT);
Pay more attention to formatting/indentation and variable naming - it will help you a lot.
#!/usr/bin/perl
use strict;
use warnings;
use LWP::UserAgent;
my $base_url = 'http://webtools.mf.uni-lj.si/public/summarisenumbers.php';
my #values = ( 'il9', 'il8', 'il6' );
my $stat_data = {};
my $browser = LWP::UserAgent->new;
$browser->timeout(10);
$browser->env_proxy;
for my $value ( #values ) {
for my $year ( 2010 .. 2013 ) {
my $query = '?query=(' . $value . ')' . $year .'[dp] NOT ' . ($year+1) . '[dp] NOT ' . ($year+2) .'[dp]';
my $url = "$base_url$query";
my $response = $browser->get( $url );
if( $response->is_success ) {
## store the fetched content in a hash structure
$stat_data->{$year}->{$value} = $response->decoded_content;
}
else {
die $response->status_line;
}
}
}
## print the header
print "\t", join( "\t", #values ), "\n";
## print the data by the years in reverse order
for my $year ( reverse sort keys %{$stat_data} ) {
print $year;
for my $value ( #values ) {
print "\t", $stat_data->{$year}->{$value};
}
print "\n";
}
Is there a module, which does this for me?
sample_input: 2, 5-7, 9, 3, 11-14
#!/usr/bin/env perl
use warnings; use strict; use 5.012;
sub aw_parse {
my( $in, $max ) = #_;
chomp $in;
my #array = split ( /\s*,\s*/, $in );
my %zahlen;
for ( #array ) {
if ( /^\s*(\d+)\s*$/ ) {
$zahlen{$1}++;
}
elsif ( /^\s*(\d+)\s*-\s*(\d+)\s*$/ ) {
die "'$1-$2' not a valid input $!" if $1 >= $2;
for ( $1 .. $2 ) {
$zahlen{$_}++;
}
} else {
die "'$_' not a valid input $!";
}
}
#array = sort { $a <=> $b } keys ( %zahlen );
if ( defined $max ) {
for ( #array ) {
die "Input '0' not allowed $!" if $_ == 0;
die "Input ($_) greater than $max not allowed $!" if $_ > $max;
}
}
return \#array;
}
my $max = 20;
print "Input (max $max): ";
my $in = <>;
my $out = aw_parse( $in, $max );
say "#$out";
A CPAN search for number range gives me this, which looks pretty much like what you're looking for:
Number::Range
Here's an example of how you can use the module in your aw_parse function:
$in =~ s/\s+//g; # remove spaces
$in =~ s/(?<=\d)-/../g; # replace - with ..
my $range = new Number::Range($in); # create the range
my #array = sort { $a <=> $b } $range->range; # get an array of numbers
Applied to the sample from the question:
Input (max 20): 2, 5-7, 9, 3, 11-14
2 3 5 6 7 9 11 12 13 14