title: Open3.popen3 function to open bz, gz, and txt files errors with 'No such file or directory' or 'not opened for reading'?
body: <p>I'm trying to write a utility function that will open three different types of files: .bz2, .gz, and .txt.  I can't just use <code>File.read</code> because it gives me garbage back for the compressed files.  I'm trying to use <code>Open3.popen3</code> so that I can give it a different command, but I'm getting a 'no such file or directory' error with the following code:</p>
  
  <pre><code>def file_info(file)
    cmd = ''
    if file.match("bz2") then
      cmd = "bzcat #{file}"# | head -20"
    elsif file.match("gz") then
      cmd = "gunzip -c #{file}"
    else
      cmd = "cat #{file}"
    end
  
    puts "opening file #{file}"
    Open3.popen3("#{cmd}", "r+") { |stdin, stdout, stderr|
      puts "stdin #{stdin.inspect}"
      stdin.read {|line|
        puts "line is #{line}"
        if line.match('^#') then
        else
          break
        end
      }
    }
  end
  
  
  &gt; No such file or directory - cat /tmp/test.txt
  </code></pre>
  
  <p>The file does exist.  I've tried using <code>cmd</code> instead of <code>#{cmd}</code> with the same results in the <code>popen3 cmd</code>.  </p>
  
  <p>I decided to hardcode it to do the txt file as follows:</p>
  
  <pre><code>def file_info(file)
    puts "opening file #{file}"
    Open3.popen3("cat", file, "r+") { |stdin, stdout, stderr|
      puts "stdin #{stdin.inspect}"
      stdin.read {|line|
        puts "line is #{line}"
        if line.match('^#') then
        else
          break
        end
      }
    }
  end
  </code></pre>
  
  <p>This gives me back:</p>
  
  <pre><code>stdin #&lt;IO:fd 6&gt;
  not opened for reading
  </code></pre>
  
  <p>What am I doing wrong? </p>
  
  <p>When I do:</p>
  
  <pre><code>Open3.popen3("cat",file) { |stdin, stdout, stderr|
    puts "stdout is #{stdout.inspect}"
    stdout.read {|line|
      puts "line is #{line}"
      if line.match('^#') then
        puts "found line #{line}"
      else
        break
      end
    }
  }
  </code></pre>
  
  <p>I get no errors and the STDOUT line is printed, but neither line statement prints out anything.</p>
  
  <p>After trying several different things, the solution I came up with was:</p>
  
  <pre><code>cmd = Array.new
  if file.match(/\.bz2\z/) then
    cmd = [ 'bzcat', file ]
  elsif file.match(/\.gz\z/) then
    cmd = [ 'gunzip', '-c', file ]
  else
    cmd = [ 'cat', file ]
  end
  
  Open3.popen3(*cmd) do |stdin, stdout, stderr|
    puts "stdout is #{stdout}"
    stdout.each do |line|
      if line.match('^#') then
        puts "line is #{line}"
      else
        break
      end
    end
  end
  </code></pre>