Forum: Ruby How to optimize my ruby code

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Valentino L. (Guest)
on 2008-11-11 14:39
I am writing a script to get the process image in unix through ssh, then
insert the record to database. As I am a new ruby user, I think my
method is quite stupid and I would like to know if you can make my code
prettier. Thanks.

Below is the ps image in my unix server (command : ps auxww)
USER         PID %CPU %MEM   SZ  RSS    TTY STAT    STIME  TIME COMMAND
\n
testrrs1 2429158  0.0  0.0 15588 15624      - A    13:27:12  0:00 java
lis.rpt.PostPrtMain /appl/lis/home2/testrrs1/config/PPRT_3.att \n
testlib  2425018  0.0  0.0 3052 4772      - A    May 29  0:00
/appl/lis/home/lib/test/work/rls_server -i/appl/lis/home/lib/test/w \n


====start of script===
require "rubygems"
$LOADED_FEATURES[$LOADED_FEATURES.length] =
'net/ssh/authentication/pageant.rb'
require 'net/ssh'
require "active_record"
$config = YAML.load_file(File.join(File.dirname(__FILE__),
'database.yml'))

ssh=Net::SSH.start("hostname", "account", :port => 12345, :paranoid =>
false, :auth_methods => ["publickey"], :passphrase => "testing", :keys
=> ["C:/testing/id_rsa"])

ps=ssh.exec!("ps auxww | head -30")
ssh.close

ps=ps.to_a
for idx in (0...ps.length)
   next if idx==0   #skip the header
   ps_user=ps[idx].split[0]
   ps_pid=ps[idx].split[1]
   ps_cpu=ps[idx].split[2]
   ps_mem=ps[idx].split[3]
   ps_sz=ps[idx].split[4]
   ps_rss=ps[idx].split[5]
   ps_tty=ps[idx].split[6]
   ps_stat=ps[idx].split[7]

   # The STIME field may equal to May 29 or 13:27:12, and the COMMAND
has unknown number of space.
   if (ps[idx].split[8].include?(":"))
      ps_stime=ps[idx].split[8]
      ps_cmd=ps[idx].split[9]+" "+ps[idx].split[10]+" "+ ... +
ps[idx].split[ps[idx].length]
   else
      ps_stime=ps[idx].split[8]+" "+ps[idx].split[9]
      ps_cmd=ps[idx].split[10]+" "+ps[idx].split[11]+" "+ ... +
ps[idx].split[ps[idx].length]
   end

   MyTable.create(:ps_user => ps_user, :ps_pid => ps_pid, ...SKIP...
:ps_cmd => ps_cmd)

end

====end of script===

Thank you very much for your kind assistance.
Brian C. (Guest)
on 2008-11-11 14:58
Valentino L. wrote:
> ps=ps.to_a
> for idx in (0...ps.length)

This is fine since you use idx later on to skip the first line, although
an alternative is

  ps.to_a.each_with_index do |line, idx|

>    next if idx==0   #skip the header
>    ps_user=ps[idx].split[0]
>    ps_pid=ps[idx].split[1]
>    ps_cpu=ps[idx].split[2]
>    ps_mem=ps[idx].split[3]
>    ps_sz=ps[idx].split[4]
>    ps_rss=ps[idx].split[5]
>    ps_tty=ps[idx].split[6]
>    ps_stat=ps[idx].split[7]

  user, pid, cpu, mem, sz, rss, tty, stat, *rest = line.split

>    # The STIME field may equal to May 29 or 13:27:12, and the COMMAND
> has unknown number of space.
>    if (ps[idx].split[8].include?(":"))
>       ps_stime=ps[idx].split[8]
>       ps_cmd=ps[idx].split[9]+" "+ps[idx].split[10]+" "+ ... +
> ps[idx].split[ps[idx].length]
>    else
>       ps_stime=ps[idx].split[8]+" "+ps[idx].split[9]
>       ps_cmd=ps[idx].split[10]+" "+ps[idx].split[11]+" "+ ... +
> ps[idx].split[ps[idx].length]
>    end

  if rest[0].include?(":")
    stime, cmd = rest[0], rest[1..-1].join(" ")
  else
    stime, cmd = rest[0]+" "+rest[1], rest[2..-1].join(" ")
  end

But a shorter (and still very efficient) way is to write a big Regexp
for matching all this:

  PS_LINE = %r{^
    (\S+) \s+  # user
    (\S+) \s+  # pid
    (\S+) \s+  # cpu
    (\S+) \s+  # mem
    (\S+) \s+  # sz
    (\S+) \s+  # rss
    (\S+) \s+  # tty
    (\S+) \s+  # stat
    (\d\d:\d\d:\d\d | \w\w\w\s\d\d) \s+  # stime
    (.*)       # cmd
  $}x

  ps.each_line do |line|
    if PS_LINE =~ line
      MyTable.create(:ps_user => $1, :ps_pid => $2, ...SKIP...
                     :ps_cmd => $10)
    end
  end

The 'x' flag to a Regexp lets you embed spaces and comments to make it
more readable. You can tweak it to match the data more precisely, e.g.
use (\d+) instead of (\S+) to match the pid, so that any unexpected
lines are ignored.
Valentino L. (Guest)
on 2008-11-11 15:33
Thank you for your clear explanation. I think I learned a great lesson.
This topic is locked and can not be replied to.