You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Ruby脚本实现类似Foreman的流式输出前置标识功能?

解决方案

串行版本脚本修改

要实现自动为输出添加当前处理项的标识前缀,核心是临时捕获标准输出(stdout),处理后再重新输出。修改后的脚本如下:

$stdin.each_line do |it|
  it.strip!
  # 保存原始标准输出对象
  original_stdout = $stdout
  # 创建StringIO对象用于捕获输出
  captured_output = StringIO.new
  $stdout = captured_output

  begin
    # 执行用户传入的代码块
    eval(ARGV.first)
  ensure
    # 恢复原始标准输出,避免影响后续操作
    $stdout = original_stdout
    # 遍历捕获的每一行输出,添加前缀后打印
    captured_output.string.each_line do |line|
      puts "[#{it}] #{line.chomp}"
    end
  end
end

并行版本脚本修改

基于Parallel库的版本,只需在每个并行处理块内复用相同的捕获逻辑(保证线程内的stdout隔离):

require 'parallel'

Parallel.each($stdin.each_line.to_a) do |it|
  it.strip!
  original_stdout = $stdout
  captured_output = StringIO.new
  $stdout = captured_output

  begin
    eval(ARGV.first)
  ensure
    $stdout = original_stdout
    captured_output.string.each_line do |line|
      puts "[#{it}] #{line.chomp}"
    end
  end
end

工作原理

  1. 捕获输出:通过将$stdout临时替换为StringIO对象,拦截用户代码块(包括system命令、puts等)产生的所有输出。
  2. 处理输出:遍历捕获到的每一行内容,为其添加[当前处理项]前缀后再打印。
  3. 安全恢复:使用ensure块保证无论代码执行成功与否,都会恢复原始的$stdout,避免破坏后续输出逻辑。

使用示例

执行命令时无需手动添加puts it,直接传入业务逻辑即可:

dir | each "Dir.chdir(it) { system('bundle') }"

输出效果自动变为:

[code] Bundle complete! 41 Gemfile dependencies, 165 gems now installed.
[code] Use `bundle info [gemname]` to see where a bundled gem is installed.
[code-ruby] Bundle complete! 6 Gemfile dependencies, 44 gems now installed.
[code-ruby] Use `bundle info [gemname]` to see where a bundled gem is installed.

内容的提问来源于stack exchange,提问作者Dorian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 04:07:15