getting stdout and stderr for system calls on windows

D

Damphyr

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

Ara.T.Howard

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", :eek:, 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
===============================================================================
 
D

Damphyr

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 :eek:utput,: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

www-data said:
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 said:
system 'echo blabla'
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", :eek:,
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


--
http://www.braveworld.net/riva

____________________________________________________________________
http://www.freemail.gr - äùñåÜí õðçñåóßá çëåêôñïíéêïý ôá÷õäñïìåßïõ.
http://www.freemail.gr - free email service for the Greek-speaking.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top