Operating System - Linux
1755696 Members
3901 Online
108837 Solutions
New Discussion юеВ

List users logged in - need way to split fields - perl?

 
SOLVED
Go to solution
Hein van den Heuvel
Honored Contributor

Re: List users logged in - need way to split fields - perl?

Oops, some cut & paste error.
This the script that worked on the sample data as I munged it:

DATA=CDRP:fapirwan;svr607:pts/4~1180963725~CDRP_PROD:cdrbatch;svr607:pts/5~1180965178~CISCO:kfulford;tmonprod01:pts/1~1180015709~CISCO:kfulford;tmonprod01:pts/2~1180038015~CORP_APPSRV:buckie;apptest2:pts/0~1180966869~DS_DATABASE_SERVERS:dbcorphd;svr032:pts/15~1173891966~


#!/usr/bin/perl

use strict;
use warnings;

my $digits = '\d+';

my $format = "%20s %20s %20s\n";
printf $format, "Userid", "Server:TTY", "Time";

my (@row, $i);

open my $dta, "-|", 'type x.txt' or die "$!";
local $/ = '~';
while (<$dta>) {
chomp;
s/^DATA=// unless $i++; # clean up header on first entry
if (/^(\d+)/) { # line with timestamp ?
my @tm = localtime $1;
my $s_time = sprintf "%2d-%02d-%4d %02d:%02d:%02d",
$tm[3], $tm[4] + 1, $tm[5] + 1900, @tm[2,1,0];
printf $format, @row[0,1], $s_time;
} else {
@row = split m/;/;
}
}
Geoff Wild
Honored Contributor

Re: List users logged in - need way to split fields - perl?

Thanks to Merijn and Hein for this most excellent perling!

Here's my final script:

#!/usr/bin/perl
#
# users-logged-in.pl
#
#
# Perl script to get a list of users logged in from the command line
#
# Note: must be in boks shell

use strict;
use warnings;

my $format = "%35s %35s %30s\n";
printf $format, "Userid", "Server:TTY", "Date Time";

my (@row, $i);

open my $dta, "-|", 'boksauth -Oresults -c FUNC=read TAB=5 FIELDS=\*|head -1' or die "$!";
local $/ = "\cB\cB";

while (<$dta>) {
chomp;
s/^DATA=// unless $i++; # clean up header on first entry
if (/^(\d+)/) { # line with timestamp ?
my @tm = localtime $1;
my $s_time = sprintf "%2d-%02d-%4d %02d:%02d:%02d",
$tm[3], $tm[4] + 1, $tm[5] + 1900, @tm[2,1,0];
printf $format, @row[0,1], $s_time;
} else {
@row = split m/\cB/;
}
}
Proverbs 3:5,6 Trust in the Lord with all your heart and lean not on your own understanding; in all your ways acknowledge him, and he will make all your paths straight.
Hein van den Heuvel
Honored Contributor

Re: List users logged in - need way to split fields - perl?

Hey Geoff.
Good to see it works!

The pipe to head is silly though!
Very non-perl thinking.

Much like the frequently seen:
cat file | grep text | awk '
Using 2 pipes instead of direct:
awk '/text/...' file

Just tell perl to do it!
Let it count lines or let it look for "\nSPLIT" (similar to the removing of "DATA=")

Now that I looked at the original topic again I have to warn you about the ^B^B line terminator approach.

>> SPLIT=^B
>> FIELDS=USER TTY ROUTE TIME INFO

It appears that the ^B^B is just an artifact of ROUTE and INFO being empty.
If those are ever filled, the script will need to be adapted.

If those new-lines after the lines are real (such as head suggest) then the data format has the potential to parse the data largely free format.

I realize this is excessive for the problem on hand but in the interested of learning and understanding consider the variant below.
The data really wants to be treated as a stream, but unfortunately the seperator is not known untill beyond the data stream. So you either have to read twice, or build an arbetrary long variable/array. Yuck to both.

Cheers,
Hein.


#!/usr/bin/perl
use strict;
use warnings;
my $format = "%20s ";

my (@fields, @values, $data, $split, $nrecords, $timefield, $i, $n, $text, $line);
#
# Get all data
#
open my $dta, "-|", 'type x.txt' or die "$!";
while (<$dta>) {
chomp;
$data = $1 if /^DATA=(.*)/;
$split = $1 if /^SPLIT=(.*)/;
@fields = split (/\s+/,$1) if /^FIELDS=(.*)/;
$nrecords = $1 if /^NRECORDS=(.*)/;
}
#
# Process header
#
@values = split $split, $data;
for ($i=0; $i<@fields; $i++) {
$timefield = $i if $fields[$i] eq 'TIME';
$text .= sprintf $format, $fields[$i];
$line .= sprintf $format, '-'x(length($format) - 1);
}
chop $text;
chop $line;
print "$text\n$line\n";
#
# Process data lines
#
$n=0;
while ($n<@values-@fields) {
$text = "";
for ($i=0; $i<@fields; $i++) {
#
# Special formatting for time field
#
if ($i==$timefield) {
my @tm = localtime $values[$n];
$values[$n] = sprintf "%2d-%02d-%4d %02d:%02d:%02d",
$tm[3], $tm[4] + 1, $tm[5] + 1900, @tm[2,1,0];

}
$text .= sprintf $format, $values[$n++];
}
print $text."\n";
}
#
# All done.
#
$n /= @fields;
print "\n\n$n records seen, $nrecords expected\n";