エスケープよりexec

HTML の実体参照化もしたほうがいいんじゃないかとそういう話もあるけれど。
そもそも、単純に IO.popen に渡すコマンドをエスケープしないといけないというのがいけてない。ポータビリティとか考え出すと恐ろしいし。
ということで、Open3.popen3 を使うか、IO.popen で "-" を指定して fork/exec するとかしたほうが良いんじゃなかろうか。こういうのね。

def popen(cmd, args, mode, &block)
   IO.popen('-', mode) do |io|
      if io
         # parent
         block.call(io)
      else
         # child
         exec(cmd, *args)
      end
   end
end

popen('ls', ARGV, 'r') do |p|
   p.each do |line|
      puts line
   end
end

Open3 を使う場合はこうか。

require 'open3'

Open3.popen3('ls', *ARGV) do |stdin, stdout, stderr|
   stdout.each do |line|
      puts line
   end
end