ciaoben
ciaoben

Reputation: 3338

How to parse and work on real time output in ruby?

I would like to do a simple thing in ruby: enter in a server , launch a tailf -f command on a log file, and perform some operation on the stream of output. (like extract some info)

How can I do it in ruby?

If a use the backtick to execute the command, the output it is never returned, is there a data structure to old this continuos output?

Upvotes: 0

Views: 844

Answers (3)

dileep nandanam
dileep nandanam

Reputation: 2895

f=File.open("path_to_log_file")
no_of_lines_per_fetch = 1
f.seek(0, no_of_lines_per_fetch)

def decision_making_function(data)
  #your logic
  puts "processing #{data}"
end

while true
  if (line=f.gets) != nil
    decision_making_function(line)
  end
end

Upvotes: 0

Jordan Running
Jordan Running

Reputation: 106027

The easiest way (and most Unix-y way) is to use the -n or -p arguments to the ruby command. From the man page (man ruby):

-n     Causes Ruby to assume the following loop around your script, which makes
       it iterate over file name arguments somewhat like sed -n or awk.

             while gets
               ...
             end

That's vague (and the "file name arguments" bit is misleading), so here's an example (let's call it sum.rb):

BEGIN {
  sum = 0
}

sum += $_.to_i

END {
  puts "Sum: #{sum}"
}

What will happen when we run this script with ruby -n is, the code in the BEGIN block will run once, then the code outside the block will run for every line of input piped to Ruby—the line is stored in $_—and then the code in the END block will run.

Suppose we have a file with the following content (let's call it data.txt):

10
15
25
50

Now we can do this:

$ cat data.txt | ruby -n sum.rb
Sum: 100

What if we only want to sum the first two numbers? Use head!

$ head -2 data.txt | ruby -n sum.rb
Sum: 25

What if we want to print every number, in addition to the sum? Use -p (for "print") instead of -n:

$ head -2 data.txt | ruby -p sum.rb
10
15
Sum: 25

The ruby command is very powerful. For example, the -a option will automatically split each line into an array and put it in $F, so if your input has two columns the first column of each line will be in $F[0], the second in $F[1], and so on. I highly recommend typing man ruby and taking a few minutes to see what options are available. Here's a good blog post that goes over some of the features: http://arjanvandergaag.nl/blog/using-ruby-command-line-options.html

One last thing: For ease of use, I recommend adding a shebang line to the top of your script, e.g.:

#!/usr/bin/env ruby -n

...and then using chmod to make your script executable (e.g. chmod ug+x sum.rb). This way your script can specify all of the arguments it needs and you can just do cat data.txt | ./sum.rb.

Upvotes: 1

Noman Ur Rehman
Noman Ur Rehman

Reputation: 6957

You can use the pty module.

You will need to do something like this:

require 'pty'

cmd = "tail -f <path-to-your-log-file>"

begin
  PTY.spawn(cmd) do |stdout, stdin, pid|
    begin
      # print output to show how it works
      # you will need to extract your info from "line" variable below
      stdout.each { |line| print line }
    rescue Errno::EIO
      puts "This means the process has finished giving output"
    end
  end
rescue PTY::ChildExited
  puts "Child process exited!"
end

Upvotes: 0

Related Questions