Robert Klemme
10/17/2008 8:37:00 AM
On 17.10.2008 00:39, Adam Skobi wrote:
> As an exercise in metaprogramming I decided to write a DSL shell. One of the
> requirements was that it should be working on both - win32 and unix
> platforms. I quickly encountered some problems with cmd.exe.
>
> My first understanding was that I open a stream to cmd.exe and write/read it
> synchronously.
You probably rather want to read asynchronously though because
synchronously does not work properly under all conditions (namely if
more data is sent back and forth than the operating system's pipe buffer
size can handle, typically 4k AFAIK). You might rather want to try this:
require 'open3'
Open3.open3 "your command" do |stdin, stdout, stderr|
threads = [
Thread.new { stdout.each {|line| puts line} },
Thread.new { stderr.each {|line| puts line} },
]
begin
...
stdin.puts "exit"
ensure
threads.each {|th| th.join}
end
end
> Everything's dandy. It works like a charm. When I try to create an
> equivalent in win32:
Do you use the native Windows Ruby or cygwin?
> IO.popen( "cmd.exe", "r+" ) do |cmd|
> cmd.puts 'cd'
> puts cmd.gets
> end
>
> This thing fails miserably. I can't really pinpoint what is the root cause
> of it.
Then what does "fails miserably" mean? Any error messages?
> I have found here on comp.lang.ruby two solutions. First one:
>
> IO.popen( "cmd.exe", "r+" ) do |cmd|
> Thread.new(cmd) do |io|
> while line = io.gets
> puts line
> end
> end
Yep, that's better anyway (see above).
> cmd.puts "dir"
> cmd.puts "cd \\"
> cmd.puts "dir"
>
> sleep 3
> end
>
> It works but is sucks badly on many levels as you can see. Other one:
You need to remember the thread and join it at the end of the block if
you want to make sure that all output from the shell is printed before
you leave the block.
> IO.popen("cmd.exe /c #{single_command}") do | pipe |
> pipe.each_line { |line| puts line }
> end
>
> This thing is not so bad but there is a small problem. I want my DSL user to
> be able to write such simple commands as
>
> cd C:> dir
>
> The problem is although the both command will run correctly, the change of
> current directory will be lost between the commands. I can think of some
> crazy workarounds but I was wondering if there is a way for the cmd.exe to
> behave normally. Any help would be appreciated.
Well, what is "normal" anyway? Not all operating systems are similar
and just because Window's shell behaves differently does not make it
abnormal. :-)
Kind regards
robert