Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Splitting Across Multiple Lines

by dru145 (Friar)
on Mar 13, 2002 at 15:59 UTC ( [id://151414]=perlquestion: print w/replies, xml ) Need Help??

dru145 has asked for the wisdom of the Perl Monks concerning the following question:

Monks,

I'm in need of your help once again. I have the following text file:
+ 192.168.89.1 acmeorp.acme.com |___ 21 File Transfer Protocol [Control] * + 192.168.31.3 ftp.acme.com |___ 21 File Transfer Protocol [Control] |___ 220 ftp.acme.com FTP server ready... * + 192.168.33.19 acmeftp.acme.com |___ 21 File Transfer Protocol [Control] |___ 220-acme Secure FTP Server.. WarFTPd 1.71.02 ( +Feb 14 2000) Ready.. (C)opyright 1996 - 2000 by Jarle (jgaa) Aase +- all righ * + 192.168.29.21 orcweb.acme.com |___ 21 File Transfer Protocol [Control] |___ 220 sandbox FTP server (Version 1.1.214.7 Thu Aug + 10 09:57:38 GMT 2000) ready... * + 192.168.11.22 commerce.acme.com |___ 21 File Transfer Protocol [Control] |___ 220 commerce Microsoft FTP Service (Version 4.0). +.. * + 192.168.19.24 webapp.acme.com |___ 21 File Transfer Protocol [Control] |___ 220 WEBAPP1PRI Microsoft FTP Service (Version 5.0 +)...
I am trying to save the ip, server name, port #, service, and description to separate arrays, but I'm having trouble since the data is not all on one line. Should I try and join the lines first? Here is what I have so far. I'm able to capture the ip and server name, but it fails to capture the rest. I know it's because of my next unless (/\*/); statement. I'm thinking I need a loop statement or two to get it to do want I want, but it's just not coming to me. I would appreciate any help. TIA
#!/usr/bin/perl -w use strict; my $infile = './ftp.txt'; my $outfile = './fileout.csv'; my (@ips, @names, @ports, @service, @desc); open INFILE, "$infile" or die "Can't open $infile: $!\n"; while (<INFILE>){ chomp; next unless (/\*/); my ($ip, $name, $port, $service, $desc) = (split /\s+/)[2,3,6]; push (@ips, $ip); push (@names, $name); push (@ports, $port); } close INFILE; foreach (@ips){ print "Here are the ip's:$_\n"; } foreach (@names){ print "Here are the server names:$_\n"; } foreach (@ports){ print "Here are the ports:$_\n"; }
Thanks,
Dru
Another satisfied monk.

Replies are listed 'Best First'.
Re: Splitting Across Multiple Lines
by ChOas (Curate) on Mar 13, 2002 at 16:05 UTC
    Hi!,

    Just to give you another option: set the input delimiter ($/)
    to a well chosen string in your text file (I would go for "* +"
    or something in your case)
    Then you can process every server individually:
    local $/="* +"; my @Serverlist=<INFILE>; for(@Serverlist) { my ($IPandName,$Protocol,$Server)=split /\n/; #Polish your info here to the real format };
    Anyhow.. that`s what I would do, the above code is just
    fictional, and untested ;))

    GreetZ!,
      ChOas

    print "profeth still\n" if /bird|devil/;
Re: Splitting Across Multiple Lines
by krazken (Scribe) on Mar 13, 2002 at 19:52 UTC
    I would look at it from a different perspective...By putting them into arrays, you lose what is associated with what, so I would look at anonymous hashes to do the trick.
    #!/usr/bin/perl -w use strict; my $ip=''; my %hash=(); while(<>) { chomp; if (/\+/) { #we have an ip address...so parse it. my $temp=$_; $temp=~s/^\+\s//g; $ip=(split (/\s/,$temp))[0]; $ip=~s/\s//g; } if ($ip !~ /\d{3}\.\d{3}\.\d{1,3}\.\d{1,3}/) { #this should never happen print STDERR "Don't have an IP address...something is not righ +t here...\n"; exit (-1); } push(@{$hash{$ip}},$_); } ###########################################3 #this will print a table like #IPADDRESS=<the ip address of the server> # SERVER=<server name> # PORTNUMBER=<port number> # SERVICE=<what service is running> # DESCRIPTION=<description of service> ####################################################### foreach my $ip_address (keys %hash) { print "IPADDRESS=$ip_address\n"; my $loop_num=0; foreach my $information (@{$hash{$ip_address}}) { #here is where you parse the information... #to get the servername, etc. #print "$information\n"; if ($loop_num == 0) { #you know this is the first entry, so this will have the s +erver name my $server=(split(/\s/,$information))[-1]; print "\t\tSERVER=$server\n"; } elsif ($loop_num == 1) { #this will have the port number if ($information =~ /(\d+)/) { my $port_number=$1; print "\t\tPORTNUMBER=$port_number\n"; } my $service=(split(/\|\_\_\_/,$information))[1]; $service=join(" ",split(" ",$service)); #need to get the port number off the front... $service=~ s/^\d+//g; $service=join(" ",split(" ",$service)); print "\t\tSERVICE=$service\n"; } elsif ($loop_num == 2) { #here is your description my $description=(split(/\|\_\_\_/,$information))[1]; $description=join(" ",split(" ",$description)); print "\t\tDESCRIPTION=$description\n"; } $loop_num++; } }
    I took the * off of the example you gave as well as fixed the word wrap that happened, and it gave the following results...
    IPADDRESS=192.168.29.21 SERVER=orcweb.acme.com PORTNUMBER=21 SERVICE=File Transfer Protocol [Control] DESCRIPTION=220 sandbox FTP server (Version 1.1.214.7 Thu Aug +10 09:57:38 GMT 2000) ready... IPADDRESS=192.168.31.3 SERVER=ftp.acme.com PORTNUMBER=21 SERVICE=File Transfer Protocol [Control] DESCRIPTION=220 ftp.acme.com FTP server ready... IPADDRESS=192.168.33.19 SERVER=acmeftp.acme.com PORTNUMBER=21 SERVICE=File Transfer Protocol [Control] DESCRIPTION=220-acme Secure FTP Server.. WarFTPd 1.71.02 (Feb +14 2000) Ready.. (C)opyright 1996 - 2000 by Jarle (jgaa) Aase - all r +igh IPADDRESS=192.168.89.1 SERVER=acmeorp.acme.com PORTNUMBER=21 SERVICE=File Transfer Protocol [Control] IPADDRESS=192.168.11.22 SERVER=commerce.acme.com PORTNUMBER=21 SERVICE=File Transfer Protocol [Control] DESCRIPTION=220 commerce Microsoft FTP Service (Version 4.0).. +. IPADDRESS=192.168.19.24 SERVER=webapp.acme.com PORTNUMBER=21 SERVICE=File Transfer Protocol [Control] DESCRIPTION=220 WEBAPP1PRI Microsoft FTP Service (Version 5.0) +...
    Output is not in the same order as the input, but you can fix that by sorting the hash keys. Anonymous hashes are my method of choice whenever I have to group lines/records by a unique key. I know this is different than you were asking, but doing it in this fashion makes it a little more flexible to work with since you know the order that the data will come in. cheers! krazken

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://151414]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (3)
As of 2024-04-20 02:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found