[#44725] Set[Set[1]]==Set[Set[1]] は偽? — "5.5" <5.5@...>

5.5 です。

22 messages 2008/03/04

[#44782] $stdin.rewind が exec した子プロセスに伝わらない? — SATOH Fumiyasu <fumiyas@...>

さとうふみやす @ OSS テクノロジです。

11 messages 2008/03/17
[#44783] Re: $stdin.rewind が exec した子プロセスに伝わらない? — Kazuhiro NISHIYAMA <zn@...> 2008/03/17

西山和広です。

[ruby-list:44788] Re: $stdin.rewind が exec した子プロセスに伝わらない?

From: SATOH Fumiyasu <fumiyas@...>
Date: 2008-03-18 09:19:21 UTC
List: ruby-list #44788
さとうふみやす @ OSS テクノロジです。

At Tue, 18 Mar 2008 17:56:03 +0900,
Nobuyoshi Nakada wrote:
> > ということで stdio を使っていないという Ruby 1.9 (1.9.0-1) で
> > 試したところ、期待通りの動作をしました。
> > 個人的にこの手の処理 (子プロセスとの IPC) は頻繁に利用するので、
> > Ruby 1.8 系列だと危なそうですね…。早く Ruby 1.9 が普及することを
> > 願ってます。(できれば協力もしたいのだけど、時間なさすぎ。)
> 
> IO.popenではうまくいかないものでしょうか。

シェルを介したくないんですが、IO.popen でできましたっけ?

コマンドインジェクションの可能性とか、シェルのメタ文字を
エスケープとか、セキュリティの不安や不確実性を
対応したり考えるのが嫌なので。なので、Kernel#system も:

  system([cmd, cmd], args)

としています。

あとは stdin だけでなく、 stderr も読みたいこともあります。
こんな感じ (某プログラムより抜粋):

  def read_file(input)
    ## Copy the target file into the local filesystem because most
    ## of the filter commands require input file must be seekable.
    input_tmp = Tempfile.new('chimera-filter')
    input_tmp.unlink
    super(input, input_tmp)
    input_tmp.rewind

    stdout_reader, stdout_writer = IO.pipe
    stderr_reader, stderr_writer = IO.pipe
    pid = Process.fork
    unless pid
      begin
	$stdin.reopen(input_tmp)
	input_tmp.close
	$stdout.reopen(stdout_writer)
	stdout_writer.close
	stdout_reader.close
	$stderr.reopen(stderr_writer)
	stderr_writer.close
	stderr_reader.close
	ENV['PATH'] = @path if (@path)
	Kernel.exec([@command, @arg0], *@args)
      rescue Exception => e
	$stderr.puts("#{$0}: ERROR: #{__FILE__}: exec failed: #{@command}: #{e}")
	exit!(1)
      end
    end
    stdout_writer.close
    stderr_writer.close

    text = String.new
    stdout_reader_th = Thread.start do
      if @read_filter
	until stdout_reader.eof?
	  text << @read_filter.call(stdout_reader.read(@read_size))
	end
      else
	until stdout_reader.eof?
	  text << stdout_reader.read(@read_size)
	end
      end
    end

    @error = nil
    stderr_reader_th = Thread.start do
      @error = stderr_reader.read
      @error = nil if @error.empty?
    end

    begin
      unless stdout_reader_th.join(@timeout)
	Process.kill('TERM', pid)
	unless stdout_reader_th.join(5)
	  Process.kill('KILL', pid)
	  stdout_reader_th.join
	end
	raise FilterCommandError.new("#{@command}: timeout (#{@timeout} sec)")
      end
    ensure
      stderr_reader_th.join
      Process.waitpid(pid)
    end

    if $?.signaled?
      raise FilterCommandError.new("#{@command}: signaled: #{$?.termsig} (SIG#{Signal.list.index($?.termsig)})")
    elsif $?.exitstatus != 0
      raise FilterCommandError.new("#{@command}: exit status: #{$?.exitstatus}")
    end

    return text
  end

我ながらうまく書けた (自画自賛 :-) と思っているんですが、
ダメ出しあるなら頂けると嬉しいです。> all

-- 
-- Name: SATOH Fumiyasu (fumiyas @ osstech co jp)
-- Business Home: http://www.OSSTech.co.jp/
-- Personal Home: http://www.SFO.jp/blog/

In This Thread