LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-19-2011, 02:35 PM   #1
0.o
Member
 
Registered: May 2004
Location: Raleigh, NC
Distribution: Debian, Solaris, HP-UX, AIX
Posts: 208

Rep: Reputation: 35
Organize Log File


Guys/Girls,

I am trying to organize a log file by user id and source IP. The data I have is in the form of the following:

Code:
user1,127.0.0.1
user2,127.0.0.2
user2,127.0.0.3
user1,127.0.0.5
...
There can be multiple source IPs associated to a single user. The way that I need the data organized is in the following format:

Code:
user1:127.0.0.1,127.0.0.5
user2:127.0.0.2,127.0.0.3
...
I have the following perl script to insert the data into a hash of arrays, but I can't seem to figure out how to put the source IPs all on one line and eliminate duplicate IPs.

Code:
#!/usr/bin/perl

use warnings;
use strict;
our %HoA = ();

open(LOG, '<', 'names_ips.csv');

while( my $line = <LOG>)
{
        my ($who, $where) = split /:\s*/, $line;
        chomp($where,$who);
        $HoA{$who} = [ $where ];
}
for my $items ( keys %HoA )
{
        print "$items,@{ $HoA{$items} }\n";
}
If someone could point me in the right direction, I would appreciate it!


Thanks!!
 
Old 05-19-2011, 04:15 PM   #2
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Perhaps someone else can help you with Perl. I'd personally just use awk for this:
Code:
awk '
BEGIN {
    RS = "[\t\n\v\f\r ]*[\n\r][\t\n\v\f\r ]*"
    FS = ",[\t\v\f ]*"
    users = 0
}

(NF > 1) {
    if (!($1 in list)) {
        user[++users] = $1
        list[$1] = ","
    }
    for (i = 2; i <= NF; i++)
        if (length($i) > 0)
            if (!index(list[$1], "," $i ","))
                list[$1] = list[$1] $i ","
}

END {
    for (u = 1; u <= users; u++) {
        thisuser = user[u]
        thislist = list[thisuser]
        sub(/^,+/, "", thislist)
        sub(/,+$/, "", thislist)
        printf("%s:%s\n", thisuser, thislist)
    }
}' logfile
This script saves user names in the user array, IP address list for each user (keyed by the user name) as a string in list array, with a comma before and after each IP address. An address is added only if it does not exist in the list; the commas make sure partial matches are not considered.

Also, note that colon (:) as a separator is a very bad idea. It makes things very difficult when you start using IPv6 addresses -- and you will, sooner or later. I recommend using either a comma or a pipe (|) instead.

Last edited by Nominal Animal; 05-19-2011 at 04:20 PM.
 
Old 05-20-2011, 01:55 PM   #3
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
I haven't tested this, but I think it looks better. The HoA needs elements added as they are found, for each user. When they are printed, they can be first turned into a scalar, using join.

Code:
#!/usr/bin/perl

use warnings;
use strict;
our %HoA = ();

open(LOG, '<', 'names_ips.csv');

while( my $line = <LOG>)
{
        my ($who, $where) = split /:\s*/, $line;
        chomp($where,$who);
        push @{$HoA{$who}}, $where;
}
for my $user ( keys %HoA )
{
        my $ipList = join ",", $HoA{$user};
        print "$user:$ipList\n";
}
--- rod.
 
Old 05-21-2011, 05:59 PM   #4
Birei
LQ Newbie
 
Registered: Nov 2010
Posts: 17

Rep: Reputation: 6
Hi,

Another solution using 'Perl':
Code:
$ cat script.pl
use warnings;
use strict;
use autodie;

@ARGV == 1 or die "Usage: perl $0 file\n";

my (%user, @fields);
open my $fh, "<", $ARGV[0];

while ( <$fh> ) {
	chomp;
	@fields = split /,/;
	push @{$user{ $fields[0] }}, $fields[1] if @fields == 2 && ! ($fields[1] ~~ @{$user{ $fields[0] }});
}

for ( sort keys %user ) {
	print $_, ":", (join ",", @{$user{ $_ }}), "\n";
}

close $fh;
$ perl script.pl infile
(Output supressed)
Regards,
Birei
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Process a log file on an hourly basis but the log only rotates once a day hattori.hanzo Programming 4 10-28-2010 08:55 AM
Clean Up Log - Search for Pattern in Log file and Output result bridrod Linux - Newbie 10 01-05-2010 09:49 AM
In Apache server, How to change log file location and log format for access log fil? since1993 Linux - Server 1 08-19-2009 04:14 PM
setting file permissions for file /var/log/Xorg.0.log mfb Linux - Security 1 07-07-2009 01:41 PM
any ideas to reduce log file size or make log file size managed? George2 Programming 2 08-13-2006 06:55 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:53 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration