有没有办法在Rails控制台内的输出上实现类似grep的功能

时间:2011-08-05 10:20:30

标签: ruby-on-rails ruby console grep

在shell中,我可以做到

$ cat name_of_file_with_a_lot_of_text | grep "What I am looking for"

在Rails控制台内部,我可以实现类似的功能,例如当我运行命令并且输出很大时,尤其是数据库查询。

我知道将它输出为YAML,但这不是我想要的。

感谢。

2 个答案:

答案 0 :(得分:19)

是的,你可以。该方法称为gr ...等待它... ep。 Ruby的grep适用于StringArray和许多其他内置对象。例如,要获取数字的所有to_xxx方法,只需执行:

 1.methods.grep(/to_/)

答案 1 :(得分:2)

我有同样的问题,并且对ream88的有点讽刺的反应不太满意,所以我决定对它进行一次破解。

# Allows you to filter output to the console using grep
# Ex:
#   def foo
#     puts "Some debugging output here"
#     puts "The value of x is y"
#     puts "The value of foo is bar"
#   end
# 
#   grep_stdout(/value/) { foo }
#   # => The value of x is y
#   # => The value of foo is bar
#   # => nil
def grep_stdout(expression)
  # First we need to create a ruby "pipe" which is two sets of IO subclasses
  # the first is read only (which represents a fake $stdin) and the second is
  # write only (which represents a fake $stdout).
  placeholder_in, placeholder_out = IO.pipe

  # This child process handles the grep'ing.  Its done in a child process so that
  # it can operate in parallel with the main process.
  pid = fork {
    # sync $stdout so we can report any matches asap
    $stdout.sync

    # replace $stdout with placeholder_out
    $stdin.reopen(placeholder_in)

    # we have to close both placeholder_out and placeholder_in because all instances
    # of an IO stream must be closed in order for it to ever reach EOF.  There's two
    # in this method; one in the child process and one in the main process.
    placeholder_in.close
    placeholder_out.close

    # loop continuously until we reach EOF (which happens when all
    # instances of placeholder_out have closed)
    read_buffer = ''
    loop do
      begin
        read_buffer << $stdin.readpartial(4096)
        if line_match = read_buffer.match(/(.*\n)(.*)/)
          print line_match[1].grep(expression)  # grep complete lines
          read_buffer = line_match[2]           # save remaining partial line for the next iteration
        end
      rescue EOFError
        print read_buffer.grep(expression)  # grep any remaining partial line at EOF
        break
      end
    end
  }

  # Save the original stdout out to a variable so we can use it again after this
  # method is done
  original_stdout = $stdout

  # Redirect stdout to our pipe
  $stdout = placeholder_out

  # sync $stdout so that we can start operating on it as soon as possible
  $stdout.sync

  # allow the block to execute and save its return value
  return_value = yield

  # Set stdout back to the original so output will flow again
  $stdout = original_stdout

  # close the main instances of placeholder_in and placeholder_out
  placeholder_in.close
  placeholder_out.close

  # Wait for the child processes to finish
  Process.wait pid

  # Because the connection to the database has a tendency to go away when calling this, reconnect here
  # if we're using ActiveRecord
  if defined?(ActiveRecord)
    suppress_stdout { ActiveRecord::Base.verify_active_connections! }
  end

  # return the value of the block
  return_value
end

我解决方案的明显缺点是输出丢失了。我不确定如何在不调用yield两次的情况下解决这个问题。

编辑我已将我的答案更改为仅调用fork一次,这样我就可以保留块的输出并在结尾处返回。取胜。

编辑2 您现在可以在此宝石中获得所有这些功能(以及更多!)https://github.com/FutureAdvisor/console_util