find the last element of a line in a file

G

gniagnia

Hi all,

here is an extract of the log file my perl script handles:

2007/02/15 17:59:22 192.168.0.12 ftpuser1 STOR 436699136 /ftp-data/
expl/data/out/region1/ftpuser1/fichier ftp de test.txt
2007/02/15 18:29:22 192.168.0.12 ftpuser1 STOR 436699136 /ftp-data/
expl/data/out/region1/ftpuser1/video.mpg
2007/02/15 17:46:31 192.168.0.12 ftpuser1 RETR - -

etc...

I'd like to record the file name at the end of each line, in an array,
in order to have :


fichier ftp de test.txt
video.mpg
etc...



So far, I manage to write this script :


push(@ftpfilesout,$1) if ( $ftpd_line =~ m:/([^/]*\S)\s*$: ) ;
foreach $ftpfileout (@ftpfilesout)
{
print "$ftpfileout";
}



But there is a problem when the script finds a line like this one :

2007/02/15 17:46:31 192.168.0.12 ftpuser1 RETR - -

(that is to say a line that doesnt contain any file name at the
end...)


How can I improve my script to bypass all lines that doesnt contains
any file name at the end?

I think the best way to do it is to record all element situated after
the 9th "/"
But I dont know how to write this...

Thanks in advance for your help!
 
M

Mirco Wahab

gniagnia said:
I'd like to record the file name at the end of each line, in an array,
in order to have :

fichier ftp de test.txt
video.mpg
etc...

So far, I manage to write this script :

push(@ftpfilesout,$1) if ( $ftpd_line =~ m:/([^/]*\S)\s*$: ) ;
foreach $ftpfileout (@ftpfilesout)
{
print "$ftpfileout";
}
No, you don't. The above is not a real Perl script.
try:

...

my @ftpfilesout = grep defined, map m{(?<=\s/).*?/([^/]+?)$}, <LOGFILE>;

print join "\n", @ftpfilesout;
...



Regards

M.
 
A

anno4000

gniagnia said:
Hi all,

here is an extract of the log file my perl script handles:

2007/02/15 17:59:22 192.168.0.12 ftpuser1 STOR 436699136 /ftp-data/
expl/data/out/region1/ftpuser1/fichier ftp de test.txt
2007/02/15 18:29:22 192.168.0.12 ftpuser1 STOR 436699136 /ftp-data/
expl/data/out/region1/ftpuser1/video.mpg
2007/02/15 17:46:31 192.168.0.12 ftpuser1 RETR - -

etc...

I'd like to record the file name at the end of each line, in an array,
in order to have :


fichier ftp de test.txt
video.mpg
etc...



So far, I manage to write this script :


push(@ftpfilesout,$1) if ( $ftpd_line =~ m:/([^/]*\S)\s*$: ) ;
foreach $ftpfileout (@ftpfilesout)
{
print "$ftpfileout";
}



But there is a problem when the script finds a line like this one :

2007/02/15 17:46:31 192.168.0.12 ftpuser1 RETR - -

(that is to say a line that doesnt contain any file name at the
end...)


How can I improve my script to bypass all lines that doesnt contains
any file name at the end?

I think the best way to do it is to record all element situated after
the 9th "/"
But I dont know how to write this...

Are you sure all lines will have exactly 9 slashes before the file name?

If so, try this:

my @files;
while ( <DATA> ) {
chomp;
push @files, m{(?:.*/){9}(.*)};
}
print "$_\n" for @files;

__DATA__
2007/02/15 17:59:22 192.168.0.12 ftpuser1 STOR 436699136 /ftp-data/expl/data/out/region1/ftpuser1/fichier ftp de test.txt
2007/02/15 18:29:22 192.168.0.12 ftpuser1 STOR 436699136 /ftp-data/expl/data/out/region1/ftpuser1/video.mpg
2007/02/15 17:46:31 192.168.0.12 ftpuser1 RETR - -

If all file names begin with "/ftp-data/expl/data/out/region1/ftpuser1/"
it would be safer to match that exact string instead of the last
seven slashes.

Anno
 
A

anno4000

Mirco Wahab said:
gniagnia said:
I'd like to record the file name at the end of each line, in an array,
in order to have :

fichier ftp de test.txt
video.mpg
etc...

So far, I manage to write this script :

push(@ftpfilesout,$1) if ( $ftpd_line =~ m:/([^/]*\S)\s*$: ) ;
foreach $ftpfileout (@ftpfilesout)
{
print "$ftpfileout";
}
No, you don't. The above is not a real Perl script.
try:

...

my @ftpfilesout = grep defined, map m{(?<=\s/).*?/([^/]+?)$}, <LOGFILE>;

The "grep defined" stage isn't really necessary here. A regex will only
return an undefined capture if the capture is in an optional part. That
doesn't happen here.

If the match fails altogether (in list context), it returns an empty
list, not undef, so map does the right thing and adds nothing.

Anno
 
M

Mirco Wahab

Mirco Wahab said:
my @ftpfilesout = grep defined, map m{(?<=\s/).*?/([^/]+?)$}, <LOGFILE>;

The "grep defined" stage isn't really necessary here. A regex will only
return an undefined capture if the capture is in an optional part. That
doesn't happen here.

If the match fails altogether (in list context), it returns an empty
list, not undef, so map does the right thing and adds nothing.

Correct.

I was under the (wrong) impression
a *non match situation* would inject
undefs. It, of course, does not.

Furthermore, the lookbehind is not necessary here
(I tried to get a non-capturing solution first), so
a simple: @stuff= map m|\s/.*?/([^/]+?)$|, <LOGFH>
would (imho) catch all.


Thanks

Mirco
 
X

Xicheng Jia

my @ftpfilesout = grep defined, map m{(?<=\s/).*?/([^/]+?)$}, <LOGFILE>;
The "grep defined" stage isn't really necessary here. A regex will only
return an undefined capture if the capture is in an optional part. That
doesn't happen here.
If the match fails altogether (in list context), it returns an empty
list, not undef, so map does the right thing and adds nothing.

Correct.

I was under the (wrong) impression
a *non match situation* would inject
undefs. It, of course, does not.

Furthermore, the lookbehind is not necessary here
(I tried to get a non-capturing solution first), so
a simple: @stuff= map m|\s/.*?/([^/]+?)$|, <LOGFH>
would (imho) catch all.

how about just removing all stuff before the last forward slash:

@stuff = map { s|.*/||; $_ } <LOGFH>

Regards,
Xicheng
 
M

Mirco Wahab

Xicheng said:
my @ftpfilesout = grep defined, map m{(?<=\s/).*?/([^/]+?)$}, <LOGFILE>;
The "grep defined" stage isn't really necessary here. A regex will only
return an undefined capture if the capture is in an optional part. That
doesn't happen here.
If the match fails altogether (in list context), it returns an empty
list, not undef, so map does the right thing and adds nothing.
Correct.

I was under the (wrong) impression
a *non match situation* would inject
undefs. It, of course, does not.

Furthermore, the lookbehind is not necessary here
(I tried to get a non-capturing solution first), so
a simple: @stuff= map m|\s/.*?/([^/]+?)$|, <LOGFH>
would (imho) catch all.

how about just removing all stuff before the last forward slash:

@stuff = map { s|.*/||; $_ } <LOGFH>

This would return matches on both lines of the OP's data:

2007/02/15 18:29:22 192.168.0.12 ftpuser1 STOR 436699136 /ftp-data/expl/data/out/region1/ftpuser1/video.mpg
2007/02/15 17:46:31 192.168.0.12 ftpuser1 RETR - -

where the alternative:

m|\s/.*?/([^/]+?)$|

would match only on the first line
(it bails out if no /'es with one [:space:] in front).

Regards

M.
 
A

anno4000

Xicheng Jia said:
Mirco Wahab <[email protected]> wrote in comp.lang.perl.misc:
my @ftpfilesout = grep defined, map m{(?<=\s/).*?/([^/]+?)$}, <LOGFILE>;
The "grep defined" stage isn't really necessary here. A regex will only
return an undefined capture if the capture is in an optional part. That
doesn't happen here.
If the match fails altogether (in list context), it returns an empty
list, not undef, so map does the right thing and adds nothing.

Correct.

I was under the (wrong) impression
a *non match situation* would inject
undefs. It, of course, does not.

Furthermore, the lookbehind is not necessary here
(I tried to get a non-capturing solution first), so
a simple: @stuff= map m|\s/.*?/([^/]+?)$|, <LOGFH>
would (imho) catch all.

how about just removing all stuff before the last forward slash:

@stuff = map { s|.*/||; $_ } <LOGFH>

That will leave line feeds at the end of each file name. It also
won't work on data that doesn't have a file name at the end -- that
was at least one problem addressed in the OP.

I am never quite happy with solutions that use s/// where
a capture would do. Simplest tool for the job, and all that...
There is usually a capturing equivalent, in this case

@stuff = map m|.*/(.+)|s, @data;

If you drop the /s, it won't capture line feeds. Of course,
it still fails on data without a file name (or, for that matter,
for file names without a slash).

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top