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

发布于 2024-11-28 02:26:51 字数 225 浏览 0 评论 0原文

在 shell 中,我可以在 Rails Console 内执行

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

,我可以实现类似的功能吗,比如当我运行命令并且输出很大时,尤其是数据库查询。

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

谢谢。

In shell, I can do

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

Inside the Rails Console, can I achieve something similar, say when I run a command and the output is huge, especially say a DB query.

I am aware of outputting it as YAML but that Is not what I am looking for.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

自由范儿 2024-12-05 02:26:51

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

 1.methods.grep(/to_/)

Yes, you can. The method is called gr... wait for it ...ep. Ruby's grep works on String, Array and many other built-in objects. For example to get all to_xxx methods of a number, just do:

 1.methods.grep(/to_/)
小草泠泠 2024-12-05 02:26:51

我也有同样的问题,并且对 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您现在可以在这个gem中获得所有这些功能(以及更多!)https: //github.com/FutureAdvisor/console_util

I had the same question and wasn't very satisfied with the somewhat snarky response from ream88, so I decided to take a crack at it.

# 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

The obvious drawback of my solution is that the output is lost. I'm not sure how to get around that without calling yield twice.

EDIT I've changed my answer to only call fork once, which allows me to keep the output of the block and return it at the end. Win.

EDIT 2 You can get all of this functionality (and more!) in this gem now https://github.com/FutureAdvisor/console_util

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文