Reading between the lines (perl or awk) - perl

Hey all, sorry for posting this here I could not find an answer anywhere and my solution is not working. I have a log file being written in the following fashion (don't ask):
=============================
04-12-2011 11:37:10 SOMETHING_GOES_HERE
Variable1
Something Goes Here
=============================
04-12-2011 11:37:20 SOMETHING_GOES_HERE
Variable2
Anything different may be here
=============================
04-12-2011 11:37:30 SOMETHING_GOES_HERE
Variable3
is altogether different here
=============================
What I'd like to do (either in perl or awk as this is an RTOS) is:
Take a look at the file, if Variable1 exists, then start at Variable2 and print everything between the equal signs:
E.g.
=============================
04-12-2011 11:37:10 SOMETHING_GOES_HERE
Variable1
Mary had a little lamb
=============================
04-12-2011 11:37:20 SOMETHING_GOES_HERE
Variable2
The cow jumped over the moon
=============================
awk '/Mary had/{getline;getline;getline;print}'
will only print
04-12-2011 11:37:20 SOMETHING_GOES_HERE
but what I need is everything between the equal signs. I tried butchering up a perl script which isn't working either. Any thoughts?
Alright, this worked (sort of)
#!perl -w
use strict;
my $LOGFILE = "/home/mydir/MyTestFile";
open my $fh, "<$LOGFILE" or die("could not open log file: $!");
my $in = 0;
while(<$fh>)
{
$in = 1 if /Variable1/i;
print if($in);
$in = 0 if /Variable2/i;
}
In the sense that a lot was stripped out. Now another q I have is selective printing a-la awk. Typically, I can get the line before something using:
echo "
test
hello
foo
bar" | awk '/foo/{print x};{x=$0}'
Will print test, however haven't found a way to get the word test (will always be a different word, but the word foo will always remain). Any takers (by the way many thanks in advance)

local $/ = "\n=============================\n";
while (<>) {
chomp;
...
}
Alternative:
my $rec = '';
while (<>) {
if (!/^=============================$/) {
$rec .= $_;
next;
}
...
$rec = '';
}
$/, chomp

I'm not totally clear on if "Variable1/2" etc are constant strings or actually varying quanitites, but does this work:
if [ $(grep Variable1 $file | wc -l) -gt 0 ]; then
sed -n '/Variable2/,/=======/' $file
fi

Related

FInd similar patterns in a row using Awk or SED

Need some help here
I have file which has multiple rows, Something like below
'**FSR**+S:KSSSSS+20+14++20120401'FST+S:KSSSSS+2'**FSR**+S:KSSSSS+44+1++20160218'
'**FSR**+S:KSSSSS+20+14++20120401'FST+S:KSSSSS+2'**FSR**+S:KSSSSS+44+1++20160218'
'**FSR**+S:KSSSSS+20+14++20120401'FST+S:KSSSSS+2'**FSR**+S:KSSSSS+44+1++20160218'
'**FSR**+S:KSSSSS+20+14++20120401'
I am trying to get all the segments within a row which begins with FSR
so results should be something like this, add pipe every time its finds a FSR, since they are constant on where they would occur in row. so i am not able to use cut here, in short FSR may come in beginning , middle or in the end of the row
'**FSR**+S:KSSSSS+20+14++20120401' | **FSR**+S:KSSSSS+44+1++20160218'
'**FSR**+S:KSSSSS+20+14++20120401' | **FSR**+S:KSSSSS+44+1++20160218'
'**FSR**+S:KSSSSS+20+14++20120401' | **FSR**+S:KSSSSS+44+1++20160218'
'**FSR**+S:KSSSSS+20+14++20120401'
Additionally, this is the code, i had written in perl, thinking if this could be could be done in simple way
#!/usr/bin/perl
use strict;
use Data::Dumper;
my $filename = $ARGV[0];
chomp($filename);
open(FILE,$filename);
my ($FSR);
while(my $data = <FILE>) {
#print $data;
($FSR) = "";
if($data =~ /('FSR.*?)(.*?)(\')/) {
$FSR = "$1,$2";
}
print "$FSR\n";
}
close(FILE);
Please help
Thanks
Sandy
EDITED:
The following one-liner would seem to address your problem as described:
$ sed -i -e 's/FSR/ | FSR/g' YOURFILE
Is there something more to this or is that what you were looking for?

Search and replace in Perl for particular word

I have a huge file which consists of similar lines below , with different clocks:
cmd -quiet [get_ports p1] ref_clocks "cudtclk_sp cudtclk"
cmd -quiet [get_ports p2] clock "cu2xdtclk_sp cu2xdtclk"
And I need to replace cudtclk with some other name like cdtclk whenever I have ref_clocks in my file, globally.
I have written following code but it doesn't seem to be working.
#!/usr/bin/perl
use strict;
use warnings;
sub clock_change
{       # Get the subroutine's argument.
my $arg = shift;
# Hash of stuff we want to replace.
my %replace = (
"cudtclk" => "cdtclk",
);
# See if there's a replacement for the given text.
my $text = $replace{$arg};
if(defined($text)) {
return $text;
}
return $arg;
}
open PAR, "<file name>";
while(<PAR>) {
$_ =~ s/\S+\s\S+\s\S+\s\S+\sref_clocks\s+(\S+\s+\S+)/clock_change($1)/eig;
print $_;   ##print it to some file later.
}
"And I need to replace cudtclk with some other name like cdtclk"
perl -pe 's/\bcudtclk\b/cdtclk/' thefile > newfile
"whenever I have ref_clocks"
perl -pe 's/\bcudtclk\b/cdtclk/ if /\bref_clocks\b/' thefile > newfile
Alternatively:
# saves original file as file.bak
perl -i.bak -pe 's/\bcudtclk\b/cdtclk/ if /\bref_clocks\b/' file
Tighten to suit your data, as necessary.
Although the substitution seems like unnecessarily complex, you can fix it with something similar to:
$_ =~ s/(ref_clocks\s+")([^_]+)_sp(\s+)\2/
$1.clock_change($2)."_sp$3".clock_change($2)/eig;

Search files and when match is found, store it, then print out 4 lines above, 3 lines below

I have a simple search script that takes user input and searches across directories & files and just lists the files it is found in. What I want to do is to be able to is when a match is found, grab 4 lines above it, and 3 lines below it and print it. So, lets say I have.
somefile.html
"a;lskdj a;sdkjfa;klsjdf a aa;ksjd a;kjaf ;;jk;kj asdfjjasdjjfajsd jdjd
jdjajsdf<blah></blah> ok ok okasdfa stes test tes tes test test<br>
blah blah blah ok, I vouch for the sincerity of my post all day long.
Even though I can sometimes be a little crass.
I would only know the blue moon of pandora if I saw it. I heard tales of long ago
times in which .. blah blah
<some html>whatever some number 76854</some html>
running thru files of grass etc.. ===> more info
whatever more "
and lets say I want to find "76854" it would print or store in an array so I can print all matches found in dirs/files.
*Match found:*
**I would only know the blue moon of pandora if I saw it. I heard tales of long ago
times in which .. blah blah
<some html>whatever whatever</some html>
running thru files of grass etc.. ===> more info
whatever more**
**********************************
Something like that. So far I have and it is working by printing out files in which it finds a match:
if ($args->{'keyword'}){
if($keyword =~ /^\d+$/){
print "Your Results are as Follows:\n";
find( sub
{
local $/;
return if ($_ =~ /^\./);
return unless ($_ =~ /\.html$/i);
stat $File::Find::name;
return if -d; #is the current file a director?
return unless -r; # is the file readable?
open(FILE, "< $File::Find::name") or return;
my $string = <FILE>;
close (FILE);
print "$keyword\n";
if(grep /$keyword/, $string){
push(#resultholder, $File::Find::name);
}else{
return;
}
},'/app/docs/');
print "Results: #resultholder\n";
}else{
print "\n\n ERROR\n";
print "*************************************\n\n";
print "Seems Your Entry was in the wrong format \n\n";
print "*************************************\n\n";
}
exit;
}
Is perl a prerequisite here? This is trivially easy with grep, you can tell it to print N number of lines before and after a match.
grep <search-term> file.txt -B <# of lines before> -A <# of lines after>
Please disregard if you really want to use perl, just throwing out an alternative.
Are you using Windows or Linux?
If you are on Linux your script is better to replace with:
grep -r -l 'search_string' path_to_search_directory
It will list you all files containing search_string. And to get 4 lines of context before and 3 lines after the line with match you need to run:
grep -r -B 4 -A 3 'search_string' path_to_search_directory
If for some reason you cannot or don't want to use grep, you need to improve your script.
First, with this construction you are reading only the first string from the file:
my $string = <FILE>;
Second, you'd better avoid reading all the file to the memory, because you can encounter several Gb file. And even reading one string to memory, because you can encounter realy large string. Replace it with sequential read to some small buffer.
And the last, to get 4 lines before and 3 lines after you need to perform reverse reading from the match found (seek to the position which is to buffer_size before the match, read that block and check if there is enough line breaks in it).
So you need to store at least 8 lines, and output those 8 lines when the 5th line matches your pattern. The shift operator, for removing an element from the front of an array, and the push operator, for adding an element to the end of a list, could be helpful here.
find( sub {
... # but don't set $\
open( FILE, '<', $File::Find::name) or return;
my #buffer = () x 8;
while (<FILE>) {
shift #buffer;
push #buffer, $_;
if ($buffer[4] =~ /\Q$keyword\E/) {
print "--- Found in $File::Find::name ---\n";
print #buffer;
# return?
}
}
close FILE;
# handle the case where the keyword is in the last ~4 lines of the file.
while (#buffer > 5) {
shift #buffer;
if ($buffer[4] =~ /\Q$keyword\E/) {
print "--- Found in $File::Find::name ---\n";
print #buffer;
}
}
} );

Perl Syntax Error : Sample Program to read a file

I am getting the an error while reading a file and below is the script.
#!/bin/bash
$file = "SampleLogFile.txt"; #--- line 2
open(MYINPUTFILE,$file); #--- line 3
while(<**MYINPUTFILE**>) {
# Good practice to store $_ value because
# subsequent operations may change it.
my($line) = $_;
# Good practice to always strip the trailing
# newline from the line.
chomp($line);
# Convert the line to upper case.
print "$line" if $line = ~ /sent/;
}
close (MYINPUTFILE);
Output :
PerlTesting_New.ksh[2]: =: not found
PerlTesting_New.ksh[3]: syntax error at line 3 : `(' unexpected
Any idea what the issue is ?
Change
#!/bin/bash
to
#!/usr/bin/perl
Otherwise Perl will not be interpreting your script. Change path accordingly as per your system
Okay, whoever is teaching you to write Perl like this needs to move out of the nineties.
#!/usr/bin/perl
use strict; # ALWAYS
use warnings; # Also always.
# When you learn more you can selectively turn off bits of strict and warnings
# functionality on an as needed basis.
use IO::File; # A nice OO module for working with files.
my $file_name = "SampleLogFile.txt"; # note that we have to declare $file now.
my $input_fh = IO::File->new( $file_name, '<' ); # Open the file read-only using IO::File.
# You can avoid assignment through $_ by assigning to a variable, even when you use <$fh>
while( my $line = $input_fh->getline() ) {
# chomp($line); # Chomping is usually a good idea.
# In this case it does nothing but screw up
# your output, so I commented it out.
# This does nothing of the sort:
# Convert the line to upper case.
print "$line" if $line = ~ /sent/;
}
You can also do this with a one liner:
perl -pe '$_ = "" unless /sent/;' SampleLogFile.txt
See perlrun for more info on one-liners.
hmm, your first line : #!/bin/bash
/bin/bash : This is the Bash shell.
You may need to change to
!/usr/bin/perl

awk to perl conversion

I have a directory full of files containing records like:
FAKE ORGANIZATION
799 S FAKE AVE
Northern Blempglorff, RI 99xxx
01/26/2011
These items are being held for you at the location shown below each one.
IF YOU ASKED THAT MATERIAL BE MAILED TO YOU, PLEASE DISREGARD THIS NOTICE.
The Waltons. The complete DAXXXX12118198
Pickup at:CHUPACABRA LOCATION 02/02/2011
GRIMLY, WILFORD
29 FAKE LANE
S. BLEMPGLORFF RI 99XXX
I need to remove all entries with the expression Pickup at:CHUPACABRA LOCATION.
The "record separator" issue:
I can't touch the input file's formatting -- it must be retained as is. Each record
is separated by roughly 40+ new lines.
Here's some awk ( this works ):
BEGIN {
RS="\n\n\n\n\n\n\n\n\n+"
FS="\n"
}
!/CHUPACABRA/{print $0}
My stab with perl:
perl -a -F\n -ne '$/ = "\n\n\n\n\n\n\n\n\n+";$\ = "\n";chomp;$regex="CHUPACABRA";print $_ if $_ !~ m/$regex/i;' data/lib51.000
Nothing is returned. I'm not sure how to specify 'field separator' in perl except at the commandline. Tried the a2p utility -- no dice. For the curious, here's what it produces:
eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z
# process any FOO=bar switches
#$FS = ' '; # set field separator
$, = ' '; # set output field separator
$\ = "\n"; # set output record separator
$/ = "\n\n\n\n\n\n\n\n\n+";
$FS = "\n";
while (<>) {
chomp; # strip record separator
if (!/CHUPACABRA/) {
print $_;
}
}
This has to run under someone's Windows box otherwise I'd stick with awk.
Thanks!
Bubnoff
EDIT ( SOLVED ) **
Thanks mob!
Here's a ( working ) perl script version ( adjusted a2p output ):
eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z
# process any FOO=bar switches
#$FS = ' '; # set field separator
$, = ' '; # set output field separator
$\ = "\n"; # set output record separator
$/ = "\n"x10;
$FS = "\n";
while (<>) {
chomp; # strip record separator
if (!/CHUPACABRA/) {
print $_;
}
}
Feel free to post improvements or CPAN goodies that make this more idiomatic and/or perl-ish. Thanks!
In Perl, the record separator is a literal string, not a regular expression. As the perlvar doc famously says:
Remember: the value of $/ is a string, not a regex. awk has to be better for something. :-)
Still, it looks like you can get away with $/="\n" x 10 or something like that:
perl -a -F\n -ne '$/="\n"x10;$\="\n";chomp;$regex="CHUPACABRA";
print if /\S/ && !m/$regex/i;' data/lib51.000
Note the extra /\S/ &&, which will skip empty paragraphs from input that has more than 20 consecutive newlines.
Also, have you considered just installing Cygwin and having awk available on your Windows machine?
There is no need for (much)conversion if you can download gawk for windows
Did you know that Perl comes with a program called a2p that does exactly what you described you want to do in your title?
And, if you have Perl on your machine, the documentation for this program is already there:
C> perldoc a2p
My own suggestion is to get the Llama book and learn Perl anyway. Despite what the Python people say, Perl is a great and flexible language. If you know shell, awk and grep, you'll understand many of the Perl constructs without any problems.