Carmen
Carmen

Reputation: 2873

How to read an open file in Ruby

I want to be able to read a currently open file. The test.rb is sending its output to test.log which I want to be able to read and ultimately send via email.

I am running this using cron:

*/5 * * * /tmp/test.rb > /tmp/log/test.log 2>&1

I have something like this in test.rb:

#!/usr/bin/ruby

def read_file(file_name)
  file = File.open(file_name, "r")
  data = file.read
  file.close
  return data
end

puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"

When I run this code, it only gives me this output:

Start

End

I would expect the output to be something like this:

Start
Start (from the reading of the test.log since it should have the word start already)
End

Upvotes: 25

Views: 97353

Answers (5)

Jini Kim
Jini Kim

Reputation: 299

class FileLineRead
  File.open("file_line_read.txt") do |file|
    file.each do |line|
      phone_number = line.gsub(/\n/,'')
      user = User.find_by_phone_number(line)
      user.destroy unless user.nil?
    end
  end
end
  1. open file
  2. read line
  3. DB Select
  4. DB Update

Upvotes: 20

the Tin Man
the Tin Man

Reputation: 160551

Ok, you're trying to do several things at once, and I suspect you didn't systematically test before moving from one step to the next.

First we're going to clean up your code:

def read_file(file_name)
  file = File.open(file_name, "r")
  data = file.read
  file.close
  return data
end

puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"

can be replaced with:

puts "Start"
puts File.read("./test.log")
puts "End"

It's plain and simple; There's no need for a method or anything complicated... yet.

Note that for ease of testing I'm working with a file in the current directory. To put some content in it I'll simply do:

echo "foo" > ./test.log

Running the test code gives me...

Greg:Desktop greg$ ruby test.rb 
Start
foo
End

so I know the code is reading and printing correctly.

Now we can test what would go into the crontab, before we deal with its madness:

Greg:Desktop greg$ ruby test.rb > ./test.log 
Greg:Desktop greg$ 

Hmm. No output. Something is broken with that. We knew there was content in the file previously, so what happened?

Greg:Desktop greg$ cat ./test.log 
Start

End

Cat'ing the file shows it has the "Start" and "End" output of the code, but the part that should have been read and output is now missing.

What happening is that the shell truncated "test.log" just before it passed control to Ruby, which then opened and executed the code, which opened the now empty file to print it. In other words, you're asking the shell to truncate (empty) it just before you read it.

The fix is to read from a different file than you're going to write to, if you're trying to do something with the contents of it. If you're not trying to do something with its contents then there's no point in reading it with Ruby just to write it to a different file: We have cp and/or mv to do those things for us witout Ruby being involved. So, this makes more sense if we're going to do something with the contents:

ruby test.rb > ./test.log.out

I'll reset the file contents using echo "foo" > ./test.log, and cat'ing it showed 'foo', so I'm ready to try the redirection test again:

Greg:Desktop greg$ ruby test.rb > ./test.log.out
Greg:Desktop greg$ cat test.log.out 
Start
foo
End

That time it worked. Trying it again has the same result, so I won't show the results here.

If you're going to email the file you could add that code at this point. Replacing the puts in the puts File.read('./test.log') line with an assignment to a variable will store the file's content:

contents = File.read('./test.log')

Then you can use contents as the body of a email. (And, rather than use Ruby for all of this I'd probably do it using mail or mailx or pipe it directly to sendmail, using the command-line and shell, but that's your call.)

At this point things are in a good position to add the command to crontab, using the same command as used on the command-line. Because it's running in cron, and errors can happen that we'd want to know about, we'd add the 2>&1 redirect to capture STDERR also, just as you did before. Just remember that you can NOT write to the same file you're going to read from or you'll have an empty file to read.

That's enough to get your app working.

Upvotes: 45

EnabrenTane
EnabrenTane

Reputation: 7466

It may be a permissions issue or the file may not exist.

f = File.open("test","r")
puts f.read()
f.close()

The above will read the file test. If the file exists in the current directory

Upvotes: 5

Nakilon
Nakilon

Reputation: 35074

The problem is, as I can see, already solved by Slomojo. I'll only add:
to read and print a text file in Ruby, just:

puts File.read("/tmp/log/test.log")

Upvotes: 4

ocodo
ocodo

Reputation: 30248

In the cron job you have already opened and cleared test.log (via redirection) before you have read it in the Ruby script.

Why not do both the read and write in Ruby?

Upvotes: 5

Related Questions