# Damn you cmd.exe!

**URL:** <https://www.ruby-forum.com/t/damn-you-cmd-exe/151115>\
**Category:** Ruby\
**Created:** [October 17, 2008, 12:40am UTC](https://www.ruby-forum.com/t/damn-you-cmd-exe/151115 "2008-10-17T00:40:43Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [October 17, 2008, 12:40am UTC](https://www.ruby-forum.com/t/damn-you-cmd-exe/151115/1 "2008-10-17T00:40:43Z")

</div>

Hi,

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. In linux it would look like this

IO.popen( “/bin/bash”, “r+” ) do |cmd|  
cmd.puts ‘pwd’  
puts cmd.gets  
end

Everything’s dandy. It works like a charm. When I try to create an  
equivalent in win32:

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. 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

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:

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.

---

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [October 17, 2008, 4:11am UTC](https://www.ruby-forum.com/t/damn-you-cmd-exe/151115/2 "2008-10-17T04:11:28Z")

</div>

cmd.exe would seem like a red herring here. Subprocesses do not modify  
the environment of their parents, whether it’s a cmd.exe process or  
whether you’ve executed ‘cd’ directly without the shell.

The case is the same on Linux and Windows. Even if Windows had a cd.exe  
executable (you could use cygwin’s cd), it wouldn’t help you.

Your purpose is unclear to me. If you want to make your own shell, you  
read the “cd” string and translate it to Dir.chdir. If you want to run  
a persistent cmd.exe, then your program is the one-liner  
exec(“cmd.exe”). Do you somehow seek something in between?

---

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [October 17, 2008, 8:14am UTC](https://www.ruby-forum.com/t/damn-you-cmd-exe/151115/3 "2008-10-17T08:14:54Z")

</div>

> 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.

Note that EventMachine has a popen that might be useful.

---

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [October 17, 2008, 9:28am UTC](https://www.ruby-forum.com/t/damn-you-cmd-exe/151115/4 "2008-10-17T09:28:22Z")

</div>

Sorry for not beeing clear enough.  
I want to have a consistent way of putting commands into the shell of  
both  
platforms - win32 and linux. The linux solution that I posted seems  
natural

- open the /bin/bash and than operate by puts and gets. I was wondering  
if  
it’s possible to do the exact same thing with the cmd.exe i.e. without  
opening the cmd.exe for each command (cmd.exe /C  
#{one\_command\_at\_a\_time})

The exec(“cmd.exe”) is not a solution as I want to have control of the  
input  
and output.

---

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [October 17, 2008, 10:45am UTC](https://www.ruby-forum.com/t/damn-you-cmd-exe/151115/5 "2008-10-17T10:45:18Z")

</div>

On 17.10.2008 00:39, Adam S. 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.

> 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

---

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [October 17, 2008, 11:32am UTC](https://www.ruby-forum.com/t/damn-you-cmd-exe/151115/6 "2008-10-17T11:32:25Z")

</div>

On Fri, Oct 17, 2008 at 10:39 AM, Robert K.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)wrote:

> 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?

Native Windows Ruby.

> Then what does “fails miserably” mean? Any error messages?

Yes i do. It writes in my native language but it translates to something  
along the lines: “The process tried to write to a non-existent stream”

> > 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.

> > dir

You see, speaking simply, I want to have control on what ‘goes in’ and  
what  
‘goes out’. I don’t want to have a background thread reading everything  
from  
cmd.exe as I wont be able to tell which command produced the output. I  
haven’t tested it thoroughly but I think it should look like in  
/bin/bash.  
Simple stuff:

shell.puts ‘cd /home/me’  
shell.puts ‘pwd’  
puts shell.gets # /home/me

I am really bedazzled as to why it doesn’t seem to work in win32.

---

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [October 17, 2008, 11:50am UTC](https://www.ruby-forum.com/t/damn-you-cmd-exe/151115/7 "2008-10-17T11:50:44Z")

</div>

On 17.10.2008 11:29, Adam S. wrote:

> On Fri, Oct 17, 2008 at 10:39 AM, Robert K.

> Native Windows Ruby.

There are some quirkynesses with that implementation which I’m not  
familiar with. I use cygwin and it has served me well.

> Yes i do. It writes in my native language but it translates to something  
> along the lines: “The process tried to write to a non-existent stream”

This works from cygwin:

irb(main):012:0\> IO.popen “cmd.exe”, “r+” do |io|  
irb(main):013:1\* t = Thread.new {io.each {|line| p line}}  
irb(main):014:1\> io.puts “dir /w”, “exit”  
irb(main):015:1\> t.join  
irb(main):016:1\> end  
“Microsoft Windows XP [Version 5.1.2600]\r\n”  
“© Copyright 1985-2001 Microsoft Corp.\r\n”  
“\r\n”  
“C:\cygwin\home\Robert\>dir /w\n”  
" Volume in Laufwerk C: hat keine Bezeichnung.\r\n"  
" Volumeseriennummer: 5C71-9E29\r\n"  
“\r\n”  
" Verzeichnis von C:\cygwin\home\Robert\r\n"  
“\r\n”  
“[.] […] .bashrc .bash\_aliases  
.bash\_history\r\n”  
“.bash\_profile .inputrc .irbrc [bin]  
x.xml\r\n”  
" 7 Datei(en) 10.364 Bytes\r\n"  
" 3 Verzeichnis(se), 57.749.262.336 Bytes frei\r\n"  
“\r\n”  
“C:\cygwin\home\Robert\>exit\n”  
=\> #\<Thread:0x7ffa6fc0 dead\>  
irb(main):017:0\>

> shell.puts ‘cd /home/me’  
> shell.puts ‘pwd’  
> puts shell.gets # /home/me
> 
> I am really bedazzled as to why it doesn’t seem to work in win32.

This solution is flawed as I have tried to explain earlier. Note that  
you will create deadlocks if you do not read the output stream properly  
(i.e. asynchronously).

If you want to make sure you know which command produced which output  
you need to nevertheless read in the background and parse output for the  
prompt. Then you know when sub process output has finished and can  
attribute the output to commands properly. You also need proper  
synchronization for this as well.

Note that you can also use File#expect.

Insisting that the world should be different won’t help because that has  
little effect on cmd.exe’s implementation. You’ll have to work with  
what you got.

robert
