title: How to capture command not found with popen4
body: <p>I'm using popen4 to capture stdout, stderr, and the exit status of a command line.  I'm not tied to popen4 as long as I can capture those 3 things above.  Currently I've not found a good way to capture command not found errors.  I could do a <code>which cmd</code> in a pre-task I suppose, but hoping for something built in.</p>
  
  <p>Below you can run a good task, bad task, and a fake task to see the differences.  I'm doing this in a fresh <code>rails new app</code> with the <code>popen4</code> gem</p>
  
  <pre><code>#!/usr/bin/env rake
  # Add your own tasks in files placed in lib/tasks ending in .rake,
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
  
  require File.expand_path('../config/application', __FILE__)
  
  require 'open4'
  
  # returns exit status 0, all is good
  task :convert_good do
    puts "convert good"
    `wget https://www.google.com/images/srpr/logo3w.png`
    status = Open4.popen4("convert logo3w.png output.jpg") do |pid, stdin,stdout,stderr|
      stdin.close
      puts "stdout:"
      stdout.each_line { |line| puts line }
      puts "stderr: #{stderr.inspect}"
      stderr.each_line { |line| puts line }
    end
    puts "status: #{status.inspect}"
    puts "exit:   #{status.exitstatus}"
  end
  
  # returns exit status 1, we messed up our command
  task :convert_bad do
    puts "convert bad"
    status = Open4.popen4("convert logo3w-asdfasdf.png output.jpg") do |pid, stdin,stdout,stderr|
      stdin.close
      puts "stdout:"
      stdout.each_line { |line| puts line }
      puts "stderr: #{stderr.inspect}"
      stderr.each_line { |line| puts line }
    end
    puts "status: #{status.inspect}"
    puts "exit:   #{status.exitstatus}"
  end
  
  # I want this to return exit code 127 for command not found
  task :convert_none do
    puts "convert bad"
    status = Open4.popen4("convert_not_installed") do |pid, stdin,stdout,stderr|
      stdin.close
      puts "stdout:"
      stdout.each_line { |line| puts line }
      puts "stderr: #{stderr.inspect}"
      #it doesnt like stderr in this case
      #stderr.each_line { |line| puts line }
    end
    puts "status: #{status.inspect}"
    puts "exit:   #{status.exitstatus}"
  end
  </code></pre>
  
  <p>Here are the 3 local outputs</p>
  
  <pre><code># good
  stdout:
  stderr: #&lt;IO:fd 11&gt;
  status: #&lt;Process::Status: pid 17520 exit 0&gt;
  exit:   0
  
  # bad arguments
  convert bad
  stdout:
  stderr: #&lt;IO:fd 11&gt;
  convert: unable to open image `logo3w-asdfasdf.png': No such file or directory @ blob.c/OpenBlob/2480.
  convert: unable to open file `logo3w-asdfasdf.png' @ png.c/ReadPNGImage/2889.
  convert: missing an image filename `output.jpg' @ convert.c/ConvertImageCommand/2800.
  status: #&lt;Process::Status: pid 17568 exit 1&gt;
  exit:   1
  
  # fake command not found, but returns exit 1 and stderr has no lines
  convert bad
  stdout:
  stderr: #&lt;IO:fd 11&gt;
  status: #&lt;Process::Status: pid 17612 exit 1&gt;
  exit:   1
  </code></pre>