0

I want to do some analysis of the Redmine log files, including the previous log. So I want to catenate logfile.log.0 and logfile.log, and loop through the output one line at a time. I wrote the following code:

module MyModule
   def analyze_log
     logfile = '/www/redmine/log/logfile.log'
     cat_cmd = "cat #{logfile}.0 #{logfile}"
     cat = IO.popen(cat_cmd)
     cat.readlines do |line|
        puts line
     end
  end
end

The code (without the module and method definition) works perfectly when I do it in irb, but on the same machine it does not work (does not print the lines) when I wrap the code in a method (analyze_log) in a module (MyModule), and call that from a script, as follows:

#!/opt/ruby/bin/ruby
require './my_module'
include MyModule
analyze_log

What gives?

BTW, if there is a better way to process multiple files sequentially in the same loop, I'd be happy to hear about it. But my main concern is that it works in irb but not when run as a script.

I AM running the script as the same user for which I ran irb.

Richard
  • 3
  • 3
  • 1
    In what way does it not work? Please post all of your code, including the module code. – Jordan Running Apr 16 '15 at 17:12
  • What do you mean by "not work"? What happens when you run the script? – toro2k Apr 16 '15 at 17:14
  • i revised the post to add the extra code. When I said "not work", I meant that no lines were printed. – Richard Apr 16 '15 at 17:24
  • change `require` to `require_relative`. `pwd` is obviously not in the path. – Aleksei Matiushkin Apr 16 '15 at 17:30
  • Did that, it didn't make a difference. And I know it's finding the module because if I add "puts 'Hello!'" to analyze_log, it does that. For that matter, I know it's creating the IO object, because if I add "p cat" after the line that creates cat, it prints "#". It just seems to be empty, as opposed to when I go through the same steps in irb. – Richard Apr 16 '15 at 17:34

3 Answers3

0

Try by changing:

cat = IO.popen(cat_cmd)

to:

cat = exec(cat_cmd)

Or change the loop to iterate over the lines to:

cat = IO.popen(cat_cmd)
cat.readlines.each {|line| puts line }
pepegasca
  • 74
  • 4
  • When you get the lines by using `cat.readlines` from `cat = IO.open(cat_cmd)`, ruby returns an array of lines not an string. In order to get working the code by using IO.popen, you need to change the loop to `cat.readlines.each{|line| puts line}` – pepegasca Apr 16 '15 at 18:08
  • `exec` actually switches the process and ends Ruby. There's no coming back from an `exec` call. There's some [nuances here](http://stackoverflow.com/questions/6338908/ruby-difference-between-exec-system-and-x-or-backticks). – tadman Apr 16 '15 at 18:10
  • editing code to propose a solution without using `exec` – pepegasca Apr 16 '15 at 18:16
0

Have you tried this:

module MyModule
   def analyze_log
     logfile = '/www/redmine/log/logfile.log'
     cat_cmd = "cat #{logfile}.0 #{logfile}"
     cat = IO.popen(cat_cmd)
     p cat.readlines
  end
end

I am still seeing why there is different behavior. Also why don't you use file class for File IO?

Akash Agrawal
  • 4,711
  • 5
  • 28
  • 26
0

A more Ruby way of doing this is to use internal functions to handle this:

module MyModule
  def analyze_log
    logfile = '/www/redmine/log/logfile.log'

    [
      "#{logfile}.0",
      logfile
    ].each do |file|
      File.readlines(file).each do |line|
        print line
      end
    end
  end
end

Running a sub-process to read a file is completely unnecessary.

tadman
  • 208,517
  • 23
  • 234
  • 262