On 11/4/2010 3:52 AM, Cai I. wrote:
> I want to do something like this:
> 
>     # open a session
>     @session = IO.popen('cmd.exe', 'r+')
> 
>     # run a command and process outputs
>     @session.puts('dir')
>     @session.each do |line|
>       p line
>     end
> 
>     # run a command line application
>     @session.puts('robocopy.exe ......')
>     @session.each do |line|
>       p line
>     end
> 
> The issue is that "@session.each" never stop. It waits when cmd.exe
> waiting for input. So the scripts hang.

The problem is that @session.each will run until the input stream is
closed, in this case until cmd.exe exits.  What you want to do is have
it run only until you get the next prompt waiting for input.  For that
you need to use something like the expect module:

require 'expect'
session = IO.popen('cmd.exe', 'r+')
session.puts('dir')
session.expect(/[CD]:\\.*>/) do
  session.puts('robocopy.exe ......')
end
session.expect(/[CD]:\\.*>/) do
  session.puts('exit')
end
session.close


The only problem with this solution is that you won't be able to see the
output of the commands you run this way.  That output is consumed by
#expect, and I don't know of a way to make it print what it consumes.
Of course another way to handle your exact example is something like this:

system('dir && robocopy.exe .......')


As long as you don't intend to process the output of commands along the
way in order to change how you run the subsequent commands, this should
work for you.  If you *do* want to process the output then you could run
each command in a separate session and read the output in between each
session:

session = IO.popen('dir')
session.each do |line|
  puts line
end
session.close

session = IO.popen('robocopy.exe .....')
session.each do |line|
  puts line
end
session.close


-Jeremy