How to read a file and save the contents till we encounter the first blank line in perl script - perl

I am trying to read a file and save the lines which starts with $path till it encounters first balnk line in an array. I have the below code, bt it only prints the path name and not the lines. Could some-one have a look.
Below are the contents of the $file:
\sbd\archieve\date\form
-rwxrwxrwx 1 etd maadm 4354270 Aug 16 21:56 COMAHCUT.dat.20120816.ftpd.201208162156*
-rw-r--r-- 1 etd maadm 0 Aug 16 21:56 COMAHCUT.DONE.20120816.ftpd.201208162156
\sbd\single\archieve\date\form
-rwxr-xr-x 1 etd maadm 1362780 Aug 15 22:02 COMAINS.dat.ftpd.201208152203*
-rwxr-xr-x 1 etd maadm 0 Aug 15 22:02 COMAINS.DONE.ftpd.201208152203*
Below is the code i tried:
#!/usr/bin/perl
my $file = "/home/pauler/practice/DataIt/line.txt";
open (INFO, $file) or die "Cannot open the file $file :$! \n";
my $path = "\sbd\archieve\date\form";
foreach $line (<INFO>) {
if ($line =~ m/$path/) {
push (#array1, $line);
last if ($line =~ m/^$/);
print #array1;
}
}

You can take advantage of the fact, that filehandles remember their position in the file.
use strict;
use warnings;
my #array;
my $path = '\sbd\archieve\date\form';
while ( my $line = <DATA> ) {
next unless $line =~ /\Q$path\E/;
push #array, $line;
while ( my $line = <DATA> ) {
last if $line =~ /^\s*$/;
push #array, $line;
}
}
print #array;
__DATA__
\sbd\archieve\date\form
-rwxrwxrwx 1 etd maadm 4354270 Aug 16 21:56 COMAHCUT.dat.20120816.ftpd.201208162156*
-rw-r--r-- 1 etd maadm 0 Aug 16 21:56 COMAHCUT.DONE.20120816.ftpd.201208162156
\sbd\single\archieve\date\form
-rwxr-xr-x 1 etd maadm 1362780 Aug 15 22:02 COMAINS.dat.ftpd.201208152203*
-rwxr-xr-x 1 etd maadm 0 Aug 15 22:02 COMAINS.DONE.ftpd.201208152203*

The flip-flop operator .. saves life ... our you code. It stays false until the expression on the left returns true, and remains true until the expression on the right turns true ... then it is false again until the left expressions evaluates to true again.
# read lines into $_ for cleaner code
while (<INFO>) {
if (/$path/ .. /^$/) {
push #array1, $_;
}
}
print #array1;
Oh, and a note on paths ... I know no single Operating System that really needs backslashes, not even Windows … Using normal slashes / will save you from weird escape sequences and other magic that lurks in the dark

Related

Perl: How come "seek" is not working

I'm trying to go through a bunch of text files twice to look for two different values. However, the seek $fh, 0, 0 doesn't seem to work. Why?
Please help
My codes:
use strict;
use warnings;
...
read_in_data_employer();
read_in_data_union();
process_files ($FileFolder);
close $FileHandle;
...
sub process_files
{
opendir (DIR, $FileFolder)
or die "Unable to open $FileFolder: $!";
my #files = grep { /.pdf.txt/ } readdir (DIR);
closedir (DIR);
#files = map { $FileFolder . '/' . $_ } #files;
foreach my $file (#files)
{
open (my $txtfile, $file) or die "error opening $file\n";
print "$file";
LookForEmployer:
{
print $FileHandle "\t";
while (my $line=<$txtfile>)
{
foreach (#InputData_Employers)
{
if ($line =~ /\Q$_/i)
{
print $FileHandle "$_";
last LookForEmployer;
}
}
}
}
seek ($txtfile, 0, 0);
LookForUnion:
{
print $FileHandle "\t";
while (my $line=<$txtfile>)
{
print "$.\n";
foreach (#InputData_Unions)
{
if ($line =~ /\Q$_/i)
{
print $FileHandle "$_";
last LookForUnion;
}
}
}
}
close $txtfile
}
}
Output:
>perl "test.pl" test "employers.txt" "unions.txt" output.txt
test/611-2643-03 (801-0741).pdf.txt12
13
14
15
16
17
18
19
20
21
22
test/611-2643-05 (801-0741).pdf.txt
7
8
9
10
11
12
test/611-2732-21 (805-0083).pdf.txt
2
3
4
5
6
7
8
test/611-2799-17 (801-0152).pdf.txt
6
7
8
9
10
11
12
13
14
Thanks
Files don't have line numbers. They don't even have lines. Files just have bytes. That means you can't just ask the system "What line of the file is at this position?"
But, since you're seeking to the start of the file, all you need is to reset $..
use Fcntl qw( SEEK_SET );
seek($txtfile, 0, SEEK_SET)
or die("seek: $!\n");
$. = 0;
By the way, you program is insanely inefficient. Load the data into hashes or into a database!

perl simple matching yet not matching it

in blah.txt:
/a/b/c-test
in blah.pl
1 my #dirs;
2 $ws = '/a/b/c-test/blah/blah'; <--- trying to match this
3 sub blah{
4 my $err;
5 open(my $fh, "<", "blah.txt") or $err = "catn do it\n";
6 if ($err) {
7 print $err;
8 return;
9 } else {
10 while(<$fh>){
11 chomp;
12 push #dirs, $_;
13 }
14 }
15 close $fh;
16 print "successful\n";
17 }
18
19
20 blah();
21
22 foreach (#dirs) {
23 print "$_\n"; #/a/b/c-test
24 if ($_ =~ /$ws/ ) { <--- didnt match it
25 print "GOT IT!\n";
26 } else {
27 print "didnt get it\n";
28 }
29 }
~
perl blah.pl
successful
/a/b/c-test
didnt get it
I am not quite sure why it is not matching.
Anyone know?
Consider,
if ($ws =~ /$_/ ) {
instead of,
if ($_ =~ /$ws/ ) {
as /a/b/c-test/blah/blah contains /a/b/c-test string, not otherwise.
As a side notes:
use at least strict and warnings
read and process file in while() loop instead of filling array first
if you must fill array, use my #dirs = <$fh>; chomp(#dirs);

looking for shell / perl script to capture the folder time stamp and the files inside the folder

I am looking for script to capture the folder time stamp and the files inside the folder
Example: I have a folder Cform12 with files inside say note1.txt , note2.rtf , note3.ldt
ls -lrt will generate drwxr-xr-x 5 r12applprd dba 4096 Dec 4 02:31 Cform12
and
ls -lrt SCF6761-PROD will generate
total 12
-rwxr-xr-x 3 r12applprd dba 4096 Dec 4 02:30 note1.txt
-rwxr-xr-x 3 r12applprd dba 4096 Dec 4 02:30 note2.rtf
-rwxr-xr-x 26 r12applprd dba 4096 Dec 4 02:31 note3.ldt
Now i have output as
Dec 4 02:31 , Cform12 , note1.txt
Dec 4 02:31 , Cform12 , note2.txt
Dec 4 02:31 , Cform12 , note3.txt
Need help me with the shell or perl script for the same.
I have created the following script to help with my question .Thanks to the contributors for all the directions
use strict;
use warnings;
my $dir = '/tmp/';
opendir(DIR, $dir) or die $!;
while (my $file = readdir(DIR)) {
next unless (-d "$dir/$file");
my $fdir = "$dir/$file";
print "$fdir\n";
my $mtime = (stat $fdir)[9];
$mtime = localtime($mtime);
$mtime = echo "$mtime" | awk '{print \$2 , \$3, \$4}' 2 > /dev/ null;
chomp($mtime);
my #files1 = find $fdir -type f | awk -F "/" '{ print \$NF }';
foreach my $fil (#files1) { print "$mtime,$file,$fil"; }
}
closedir(DIR);
exit 0;
I think this script will help you if my understanding is correct..
use strict;
use warnings;
my $path="/var/inner";#directory absolute path
my $mtime=(stat $path)[9];
my $name=`basename $path`;
chomp($name);
$mtime= localtime($mtime);
$mtime=`echo "$mtime" | awk '{print \$2 , \$3, \$4}'`;
chomp($mtime);
my #files = glob("$path/*");
foreach my $file(#files){
print "$mtime , $name , ".`basename $file`;
}
The script below does the same but recursively. Is this what you want?
use strict;
use warnings;
my $path="/export/home/tarumugam/shellshop";#directory absolute path
sub rotator{
(my $path)=#_;
my $mtime=(stat $path)[9];
my $name=`basename $path`;
chomp($name);
$mtime= localtime($mtime);
$mtime=`echo "$mtime" | awk '{print \$2 , \$3, \$4}' 2> /dev/null`;
chomp($mtime);
my #files = glob("$path/*");
foreach my $file(#files){
if(-f $file){
print "$mtime , $name , ".`basename $file`;
}else{
rotator($file);
}
}
}
rotator($path);
Are you looking for something like the following?
$ stat -c "%x" src; find src -mindepth 1 -maxdepth 1 -exec basename '{}' \;
2013-12-03 22:39:42.911796567 -0500
UndirectedGraphClient.java
UndirectedGraph.java
Bag.java
A bash scripting guide could help you out a lot. Maybe take a look at http://mywiki.wooledge.org/BashGuide or http://wiki.bash-hackers.org/doku.php ?

Perl Format the Output in nice way

I have written a perl code for processing file 'Output.txt' which has below Content.
new.example.com 28
new.example.com 28
example.com 28
example.com 29
example.com 29
example.com 29
example.com 29
orginal.com 28
orginal.com 29
orginal.com 30
orginal.com 31
expand.com 31
And file 'domain.txt' has list of domain Names which i need to match against File 'Output.txt'
new.example.com
example.com
orginal.com
test.com
new.com
I could manage to write PERL code like this
#!/usr/bin/perl
use strict;
open(LOGFILE,"Output.txt") or die("Could not open log file.");
my $domain_name = 'domain.txt' ;
open(DOM, $domain_name);
my #r_contents = <LOGFILE>;
close(LOGFILE);
while(<DOM>) {
chomp;
my $line = $_;
my #lowercase = map { lc } #r_contents;
my #grepNames = grep /^$line/, #lowercase;
foreach (#grepNames) {
if ( grep /^$line/, #lowercase ) {
$domains{lc($_)}++ ; }
}
}
close(DOM) ;
foreach my $domain (sort keys %domains) {
my %seen ;
($Dname, $WeekNum) = split(/\s+/, $domain);
my #array1 = grep { ! $seen{ $_ }++ } $WeekNum;
push #array2, #array1;
my #array4 = "$domains{$domain} $domain" ;
push #matrix,#array4 ;
}
printf "%-10s %-25s %-25s\n", 'DoaminName', "Week $array2[0]" ,"Week $array2[1]","Week $array2[2]";
print " #matrix \n";
current Output looks like this.
DoaminName Week 28 week29 week30 week 31
2 new.example.com 35
1 example.com 28
4 example.com 29
1 orginal.com 28
1 orginal.com 29
1 orginal.com 30
1 orginal.com 31
But i trying re-write the perl code to print the output like this .Please help me to correct the code.
Domain/WeekNumber Week28 Week29 Week30 Week31
new.example.com 2 No No No
example.com 1 4 NO NO
orginal.com 1 1 1 1
This produces the desired output, only I also sorted the output.
If you have long website names, add tabs in the code as necessary.
#!/usr/bin/perl
use warnings;
use strict;
open my $fh, "<", "Output.txt" or die "could not open Output.txt\n";
my %data;
my %weeks;
while(<$fh>){
chomp;
$_=~ m/(.*?)\s++(\d++)/;
my $site=$1;
my $week=$2;
$weeks{$week}++;
$data{$site}{$week}++;
}
print "Domain/WeekNumber";
for my $week (sort {$a <=> $b} keys %weeks){
print"\tWeek$week";
}
print"\n";
for my $site(sort keys %data){
print"$site\t\t";
for my $week (sort {$a <=> $b} keys %weeks){
unless(defined $data{$site}{$week} ){
print"NO\t";
}else{
print $data{$site}{$week} ."\t";
}
}
print"\n";
}
close $fh;

perl help to parse log file based on time input

Perl newbie here. I have a log file that I need to parse out "Backup succeeded" and any "Error:" entries. I tried parsing the log file by using unix cat and piping it to grep. I got the information that I want, but I would like try this in perl and to also have the option to pass a date parameter and give me the lines based on the date I need.
Sample of log file output: (Backup succeeded)
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: flush-logs-time=00:00:00
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: backup-time=06:14:23
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: backup-status=Backup succeeded
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: Backup succeeded
Sample of log file output: (Error:)
Wed Jun 09 05:00:03 2010: rip1.mil.mad:backup:ERROR: mysql-zrm appears to be already running for this backupset
Wed Jun 09 05:00:03 2010: rip1.mil.mad:backup:ERROR: If you are sure mysql-zrm is not running, please remove the file /etc/mysql-zrm/rip1.mail.mad/.mysql-zrm.pid and restart mysql-zrm
**I would like a text and/or email with this information. Like so, but with the option to pass in the date I need.
Wed Jun 09 05:00:03 2010: rip1.mil.mad:backup:ERROR: mysql-zrm appears to be already running for this backupset
Wed Jun 09 05:00:03 2010: rip1.mil.mad:backup:ERROR: If you are sure mysql-zrm is not running, please remove the file /etc/mysql-zrm/rip1.mail.mad/.mysql-zrm.pid and restart mysql-zrm
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: backup-status=Backup succeeded
If you would please provide me with some perl code and/or ideas to get started. I would appreciate the help. Thank you.
#!/usr/bin/perl
# usage example: <this script> Jun 09 2010 <logfile>
use strict;
use warnings;
my ($mon,$day,$year) = ($ARGV[0],$ARGV[1],$ARGV[2]);
open(FH,"< $ARGV[3]") or die "can't open log file $ARGV[3]: $!\n";
while (my $line = <FH>) {
if ($line =~ /.* $mon $day \d{2}:\d{2}:\d{2} $year:.*(ERROR:|Backup succeeded)/) {
print $line;
}
}
Here's a simple script. The file name to scan and the target date are hard-coded. Matches are printed to STDOUT.
BTW, this code is totally untested. I typed it into the text box in my browser.
use strict;
use warnings;
my $logpath = './bar/log';
my $target = 'Jun 09 2010';
open my $fh, '<', $logpath or die "Error opening $logpath $!\n";
while (my $line = <$fh> ) {
next unless date_match( $target, $line );
next unless my $result = got_error($line) // got_backup($line);
print $result;
}
sub got_backup {
my $line = shift;
return unless $line =~ /backup-status=Backup succeeded/;
return $line;
}
sub got_error {
my $line = shift;
return unless $line =~ /:ERROR:/;
return $line;
}
# Take a line and a target date. Compare the date derived from the line to
# the target, and returns true if they match.
# Also always returns true if target is not defined
sub date_match {
my $target = shift;
my $line = shift;
return 1 unless defined $target; # Always true if target is undefined.
# Where did that god-awful date format come from? Yech.
my $date = extract_date($line);
return $date eq $target;
}
# Simple extract of date using split and join with extra variables
# to make it newbie friendly.
# IMO, it would be a good idea to switch to using DateTime objects and
# DateTime::Format::Strptime
sub extract_date {
my $line = shift;
my #parts = split /:/, $line;
my $date = join ':' #parts[0..2];
#parts = split /\s+/, $date;
$date = #parts[1,2,4];
return $date;
}
You can use Getopt::Long to get a filename and target date.
It would be a good idea to use a more robust date/time parsing and comparison scheme. DateTime and friends are very good, powerful modules for date manipulation. Check them out.
If you are processing tons of data and need to be more efficient, you can avoid copying $line everywhere in a number of ways.
For future reference, if you post a little code, you'll get better responses