Finding last line in a file

Hi everyone,

Is there a one line command to do this?

I mean currently I use

File.foreach(inFile) do |line|
...
done

I could do this with a counter, but that is SO UGLY, and I want to do an
operation on that very last line.

Regards,
Ted.

···

--
Posted via http://www.ruby-forum.com/.

last_line = ''
IO.popen("tail -n 1 #{file_name}") { |f| last_line = f.gets }

Regards,
Prasad C

···

On Thu, Jul 22, 2010 at 9:51 AM, Ted Flethuseo <flethuseo@gmail.com> wrote:

Hi everyone,

Is there a one line command to do this?

I mean currently I use

File.foreach(inFile) do |line|
...
done

I could do this with a counter, but that is SO UGLY, and I want to do an
operation on that very last line.

Regards,
Ted.
--
Posted via http://www.ruby-forum.com/\.

Take a look at the doc for File.readline.

(2010/07/22 14:08), Urabe Shyouhei wrote:

Take a look at the doc for File.readline.

Oops... typo. I meant readlines. With it you can do something like
File.readlines(f).last

This is as inefficient as using File.foreach because it will read the whole file. I believe Ted was looking for a more efficient solution.

Ted, if you want to do this in Ruby and not resort to tail you can use IO#seek to seek to the end of the file and read backwards until you have read more than one line.

Kind regards

  robert

···

On 07/22/2010 07:10 AM, Urabe Shyouhei wrote:

(2010/07/22 14:08), Urabe Shyouhei wrote:

Take a look at the doc for File.readline.

Oops... typo. I meant readlines. With it you can do something like
File.readlines(f).last

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

I think this is the algorithm used by James Gray in Elif:

http://elif.rubyforge.org/

From those docs:

" gets(sep_string = $/)

The second half on the Elif algorthim (see Elif::new). This method
returns the next line of the File, working from the end to the
beginning in reverse line order.

It works by moving the file pointer backwords MAX_READ_SIZE at a time,
storing seen lines in @line_buffer. Once the buffer contains at least
two lines (ensuring we have seen on full line) or the file pointer
reaches the head of the File, the last line from the buffer is
returned. When the buffer is exhausted, this will throw nil (from the
empty Array)."

Jesus.

···

On Thu, Jul 22, 2010 at 8:35 AM, Robert Klemme <shortcutter@googlemail.com> wrote:

On 07/22/2010 07:10 AM, Urabe Shyouhei wrote:

(2010/07/22 14:08), Urabe Shyouhei wrote:

Take a look at the doc for File.readline.

Oops... typo. I meant readlines. With it you can do something like
File.readlines(f).last

This is as inefficient as using File.foreach because it will read the whole
file. I believe Ted was looking for a more efficient solution.

Ted, if you want to do this in Ruby and not resort to tail you can use
IO#seek to seek to the end of the file and read backwards until you have
read more than one line.

(2010/07/22 15:35), Robert Klemme wrote:

···

On 07/22/2010 07:10 AM, Urabe Shyouhei wrote:

(2010/07/22 14:08), Urabe Shyouhei wrote:

Take a look at the doc for File.readline.

Oops... typo. I meant readlines. With it you can do something like
File.readlines(f).last

This is as inefficient as using File.foreach because it will read the
whole file. I believe Ted was looking for a more efficient solution.

Then how about:

File.open(f).each_line.inject(nil){|x,y|y}

Slower than my first answer though.

Robert Klemme wrote:

···

On 07/22/2010 07:10 AM, Urabe Shyouhei wrote:

(2010/07/22 14:08), Urabe Shyouhei wrote:

Take a look at the doc for File.readline.

Oops... typo. I meant readlines. With it you can do something like
File.readlines(f).last

This is as inefficient as using File.foreach because it will read the
whole file. I believe Ted was looking for a more efficient solution.

Ted, if you want to do this in Ruby and not resort to tail you can use
IO#seek to seek to the end of the file and read backwards until you have
read more than one line.

Kind regards

  robert

Interesting, the problem is how to find how far back I need to go in the
seek (automatically of course)

  f = File.new("testfile")
  f.seek(-13, IO::SEEK_END) #=> 0
  f.readline #=> "And so on...\n"

Ted.
--
Posted via http://www.ruby-forum.com/\.

This still reads in the whole file plus you do not close the File
object properly. A solution that is efficient for large files will
use File#seek to move position to the end of the file and go backwards
from there.

Cheers

robert

···

2010/7/22 Urabe Shyouhei <shyouhei@ruby-lang.org>:

(2010/07/22 15:35), Robert Klemme wrote:

On 07/22/2010 07:10 AM, Urabe Shyouhei wrote:

(2010/07/22 14:08), Urabe Shyouhei wrote:

Take a look at the doc for File.readline.

Oops... typo. I meant readlines. With it you can do something like
File.readlines(f).last

This is as inefficient as using File.foreach because it will read the
whole file. I believe Ted was looking for a more efficient solution.

Then how about:

File.open(f).each_line.inject(nil){|x,y|y}

Slower than my first answer though.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

(2010/07/22 22:06), Robert Klemme wrote:

Then how about:

File.open(f).each_line.inject(nil){|x,y|y}

Slower than my first answer though.

This still reads in the whole file plus you do not close the File
object properly.

I'm sure you know how to do that properly.

A solution that is efficient for large files will
use File#seek to move position to the end of the file and go backwards
from there.

No, that can't work -- or that works only when you are sticking on the ASCII
character set. Multibyte encodings are not safe to read backwards
(sometimes). The only safe way is to read the whole content from the
beginning, at least one time.

Check the elif gem, by James Edward Gray II.

It is a port of File::ReadBackwards, whose documentation explains the approach:

    http://search.cpan.org/~uri/File-ReadBackwards-1.04/ReadBackwards.pm#DESIGN

-- fxn

Good point. Although pragmatically for fixed width and UTF-8 encoded files it will work and the performance gains for large files are significant enough to warrant this approach.

Cheers

  robert

···

On 22.07.2010 16:22, Urabe Shyouhei wrote:

(2010/07/22 22:06), Robert Klemme wrote:

Then how about:

File.open(f).each_line.inject(nil){|x,y|y}

Slower than my first answer though.

  A solution that is efficient for large files will
use File#seek to move position to the end of the file and go backwards
from there.

No, that can't work -- or that works only when you are sticking on the ASCII
character set. Multibyte encodings are not safe to read backwards
(sometimes). The only safe way is to read the whole content from the
beginning, at least one time.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

(2010/07/22 23:33), Xavier Noria wrote:

Check the elif gem, by James Edward Gray II.

It is a port of File::ReadBackwards, whose documentation explains the approach:

    http://search.cpan.org/~uri/File-ReadBackwards-1.04/ReadBackwards.pm#DESIGN

And says nothing about multiligualization because M17N cannot be achieved by
the approach, theoretically.

Maybe that's OK for Ted. I'm living in a different world than you perhaps.

Yes, I wrote it before Ruby 1.9's m17n engine. I only use it on ASCII logs, where it works fine. I would not recommend it for encoded data.

James Edward Gray II

···

On Jul 22, 2010, at 10:36 AM, Urabe Shyouhei wrote:

(2010/07/22 23:33), Xavier Noria wrote:

Check the elif gem, by James Edward Gray II.

It is a port of File::ReadBackwards, whose documentation explains the approach:

   http://search.cpan.org/~uri/File-ReadBackwards-1.04/ReadBackwards.pm#DESIGN

And says nothing about multiligualization because M17N cannot be achieved by the approach, theoretically.

So in general you can't detect character boundaries going backwards?
You can always have cut characters and still have a valid buffer?

···

On Thu, Jul 22, 2010 at 5:36 PM, Urabe Shyouhei <shyouhei@ruby-lang.org> wrote:

And says nothing about multiligualization because M17N cannot be achieved by
the approach, theoretically.