rubyprocessspawn

Ruby Spawn not accepting a IO.pipe


I searched around but I cannot get to understand why I am getting the error:

"in `spawn': no implicit conversion of IO into String"

for the following simple method

def execute_with_timeout(cmd)
  pipe_cmd_out = IO.pipe
  pid = Process.spawn(cmd, :out => pipe_cmd_out, :pgroup => true)
  Process.waitpid(pid, 0)
  pipe_cmd_out.close
  $?.exitstatus == 0
end

where am I making the error here?


Solution

  • The redirection maps a file descriptor in the child process, e.g. :out (or STDOUT or 1) to one of:

    1. io: a file descriptor specified as io.fileno
      ...
      ...

    From the pipe() docs:

    pipe() -> [read_io, write_o]:
    Creates a pair of pipe endpoints (connected to each other) and returns them as a two-element array of IO objects: [ read_io, write_io ].

    http://ruby-doc.org/core-2.2.0/IO.html#method-c-pipe

    So, you can do this:

    def execute_with_timeout(cmd)
      reader, writer = IO.pipe
      puts reader, writer
    
      pid = Process.spawn(
        cmd, 
        :pgroup => true,
        :out => writer.fileno,  #Redirect child STDOUT into one end of the pipe.
      )
    
      Process.waitpid(pid, 0)
    
      puts reader.gets  #Read from the other end of the pipe in the parent.
    
      writer.close
      reader.close
    
      $?.exitstatus == 0
    end
    
    result = execute_with_timeout('ls')
    puts result
    
    --output:--
    #<IO:0x000001009a0140>
    #<IO:0x000001009a0118>
    1.rb
    true
    

    where am I making the error here?

    The spawn() docs say:

    For redirecting to a file, an array is used instead:

     id = spawn(command, :out=>["log", "w"])  
    

    The array specifies a filename, flags and permission.

    http://ruby-doc.org/core-2.1.3/Process.html#method-c-spawn

    Your pipe() call returns an array of IO objects, which you used for the value of the :out key. But because spawn() is expecting an array of Strings as a value, ruby tries to convert the IO objects to Strings, which produces the error:

    "in `spawn': no implicit conversion of IO into String"
    

    The spawn() docs do show an example where the value corresponding to one of the redirect keys is not an array of strings:

     :err=>[:child, :out]
    

    (which means redirect :err(in the child) to child :out). But your pipe() array is not an array of Symbols either.