Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

getting stdout and stderr for system calls on windows

58 views
Skip to first unread message

Damphyr

unread,
Nov 23, 2005, 11:01:09 AM11/23/05
to
OK, I'm stuck with a pretty problem:
I need to drive a build process using make (dmake) from my scripts and I
want to capture stdout and stderr as well as the return value from dmake.
Normally I would do it using Daniel Berger's win32-popen3, but I have a
Windows Installer Ruby with VC++6.0 which nastily gives me a segfault
(properly documented in the README, but still a segfault :) ).
Recompiling Ruby is a no-no and changing VC compiler also a no-no.

Now, does anyone have a quick solution for me?
Is there anyway to call say:

system 'echo blabla'

and to redirect stdout and stderr used by system? (I guess not).
Any help is appreciated.
I am aware of

IO.popen("dmake target 2>&1") {|f|
output = f.read
exitcode = Process.waitpid2(f.pid)[1]
}
and is currently my best choice, although I would like to split stderr
and stdout.

Cheers,
V.-
--
http://www.braveworld.net/riva

____________________________________________________________________
http://www.freemail.gr - δωρεάν υπηρεσία ηλεκτρονικού ταχυδρομείου.
http://www.freemail.gr - free email service for the Greek-speaking.


Berger, Daniel

unread,
Nov 23, 2005, 11:11:28 AM11/23/05
to

> -----Original Message-----
> From: Damphyr [mailto:dam...@freemail.gr]
> Sent: Wednesday, November 23, 2005 9:01 AM
> To: ruby-talk ML
> Subject: getting stdout and stderr for system calls on windows
>
>
> OK, I'm stuck with a pretty problem:
> I need to drive a build process using make (dmake) from my
> scripts and I
> want to capture stdout and stderr as well as the return value
> from dmake. Normally I would do it using Daniel Berger's
> win32-popen3, but I have a
> Windows Installer Ruby with VC++6.0 which nastily gives me a segfault
> (properly documented in the README, but still a segfault :)
> ). Recompiling Ruby is a no-no and changing VC compiler also a no-no.

If anyone knows of a magic compatibility switch to cl or link that will
prevent this, I'm all ears. :)

Dan

Ara.T.Howard

unread,
Nov 23, 2005, 12:34:45 PM11/23/05
to
On Thu, 24 Nov 2005, Damphyr wrote:

> OK, I'm stuck with a pretty problem:
> I need to drive a build process using make (dmake) from my scripts and I
> want to capture stdout and stderr as well as the return value from dmake.
> Normally I would do it using Daniel Berger's win32-popen3, but I have a
> Windows Installer Ruby with VC++6.0 which nastily gives me a segfault
> (properly documented in the README, but still a segfault :) ). Recompiling
> Ruby is a no-no and changing VC compiler also a no-no.
>
> Now, does anyone have a quick solution for me? Is there anyway to call say:
>
> system 'echo blabla'
>
> and to redirect stdout and stderr used by system? (I guess not).
> Any help is appreciated.
> I am aware of
>
> IO.popen("dmake target 2>&1") {|f|
> output = f.read
> exitcode = Process.waitpid2(f.pid)[1]
> }
> and is currently my best choice, although I would like to split stderr and
> stdout.
>
> Cheers,
> V.-

i was working on this at one point:

harp:~ > cat a.rb
class Redirector
require "tempfile"
attr_accessor "ruby"
def initialize
@ruby = "ruby"
@script = tempfile
@script.write <<-ruby
stdout, stderr = ARGV.shift, ARGV.shift
File::unlink out rescue nil
File::unlink err rescue nil
STDOUT.reopen(open(stdout,"w"))
STDERR.reopen(open(stderr,"w"))
system(ARGV.join(' '))
ruby
@script.close
end
def run command, redirects = {}
stdout = redirects.values_at("stdout", :stdout, "o", :o, 1).compact.first
tout = nil
unless stdout
tout = tempfile
stdout = tout.path
end
stderr = redirects.values_at("stderr", :stderr, "e", :e, 2).compact.first
terr = nil
unless stderr
terr = tempfile
stderr = terr.path
end
system "#{ @ruby } #{ @script.path } #{ stdout } #{ stderr } #{ command }"
ret = IO::read(stdout), IO::read(stderr), $?.exitstatus
tout.close! if tout
terr.close! if terr
ret
end
def tempfile
Tempfile::new(Process::pid.to_s << rand.to_s)
end
end

redirector = Redirector::new

stdout, stderr, exitstatus = redirector.run "echo 42"
p [stdout, stderr, exitstatus]

redirector.run "echo 42", 1 => "out", 2 => "err"
p [IO::read("out"), IO::read("err")]


harp:~ > ruby a.rb
["42\n", "", 0]
["42\n", ""]

regards.

-a
--
===============================================================================
| ara [dot] t [dot] howard [at] noaa [dot] gov
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| -- bodhicaryavatara
===============================================================================

www-data

unread,
Dec 5, 2005, 7:06:36 PM12/5/05
to
I have the same problem, and i'm likely going to end up using this
syntax inside a system call:

(((dmake target | tee stdout.txt) 3>&1 1>&2 2>&3 | tee stderr.txt) 3>&1
1>&2 2>&3) 2>&1 | tee output.txt

where output.txt will contain stderr + stdout
stdout.txt will contain stdout
stderr.txt will contain stderr

There is a description of how this works here:
http://www.cpqlinux.com/redirect.html
Scroll down to "Capturing stderr with tee Swapping stderr and stdout"
Ugly as hell but it does the trick... hopefully someone knows a cleaner
way to do this within ruby?

--

ara.t.howard wrote:
> On Thu, 24 Nov 2005, Damphyr wrote:
>

>> system 'echo blabla'


--
Posted via http://www.ruby-forum.com/.


Damphyr

unread,
Dec 8, 2005, 4:58:48 PM12/8/05
to
I ended up with the following after this discussion. It doesn't separate
stderr and stdout, but for what I want it, it's more than enough. And I
added crude benchmarking as well:) :
There was also an exitcode method in there (you can get the exitcde from
@process).

#Executes a command on a dos shell, redirecting stderr to stdout ("2>&1")
#
#You can then access the output and the return value for the command.
#
#This is meant as a last-resort replacement for popen3 (because of
problems with VC++6.0 and the Ruby One-Click Installer).
#
#_exec_time_ provides the Time spent running the command.
class ExecCmd
attr_reader :output,:cmd,:exec_time
#When a block is given, the command runs before yielding
def initialize cmd
@output=""
@exec_time=0
@cmd=cmd
@cmd_run=cmd+" 2>&1" unless cmd=~/2>&1/
if block_given?
run
yield self
end
end

#Runs the command
def run
t1=Time.now
IO.popen(@cmd_run){|f|
@output=f.read
@process=Process.waitpid2(f.pid)[1]
}
@exec_time=Time.now-t1
end
#Returns false if the command hasn't been executed yet
def run?
return false unless @process
return true
end
#Returns true if the command was succesfull.
#
#Will return false if the command hasn't been executed
def success?
return @process.success? if @process
return false
end
end


--

0 new messages