Techioz Blog

ストリーミング中に職長のように出力を先頭に追加する

概要

私はよく使う Ruby スクリプトがあります。

$stdin.each_line do |it|
  it.strip!
  eval(ARGV.first)
end

例えば:

> dir | each "Dir.chdir(it) { puts it; system('bundle') }"
code
Bundle complete! 41 Gemfile dependencies, 165 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
code-ruby
Bundle complete! 6 Gemfile dependencies, 44 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

私はこの「puts it」を頻繁に行うので、むしろ出力の前に「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.

これは、並列バージョンではさらに明らかです。

Parallel.each($stdin.each_line.to_a) do |it|
  it.strip!
  eval(ARGV.first)
end

解決策

%x(cmd) または を使用して出力をキャプチャし、フォーマットします。

# each.rb

#!/usr/bin/env ruby

def command prefix, cmd
  out = %x(#{cmd})
  out.split("\n").each do |line|
    puts "[#{prefix}] #{line}"
  end
end

$stdin.each_line do |it|
  it.strip!
  eval(ARGV.first)
end
$ pwd | ./each.rb "command(it, 'bundle')"
[/home/alex/code/stackoverflow] Bundle complete! 54 Gemfile dependencies, 163 gems now installed.
[/home/alex/code/stackoverflow] Use `bundle info [gemname]` to see where a bundled gem is installed.

https://translate.google.com/translate?hl=ja&sl=en&tl=ja&u=https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-25x-3A+Backtick+Literals

このアプローチの唯一の問題は、出力を表示するにはコマンドを最後まで実行する必要があることです。

書き込み中の出力を確認したい場合は、システム出力をオーバーライドできます。

def command prefix, cmd
  rd, wr = IO.pipe
  Thread.new do
    system(cmd, out: wr)
    wr.close
  end

  until rd.eof?
    line = rd.gets
    puts "[#{prefix}] #{line}"
  end
  rd.close
end

$stdin.each_line do |it|
  it.strip!
  eval(ARGV.first)
end
$ pwd | ./each.rb "command it, 'for j in 1 2 3; do echo \$j; sleep 1; done'"
[/home/alex/code/stackoverflow] 1
[/home/alex/code/stackoverflow] 2
[/home/alex/code/stackoverflow] 3

https://translate.google.com/translate?hl=ja&sl=en&tl=ja&u=https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-File+Redirection+-28File+Descriptor-29