Forum: Ruby getting stdout and stderr for system calls on windows

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Cfdeff3ac35010e4de8f85d954f24f4a?d=identicon&s=25 damphyr (Guest)
on 2005-11-23 17:02
(Received via mailing list)
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
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 ara.t.howard (Guest)
on 2005-11-23 18:35
(Received via mailing list)
On Thu, 24 Nov 2005, Damphyr wrote:

> 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", :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
452a25352d79546c9380c352e2032f8f?d=identicon&s=25 anon (Guest)
on 2005-12-06 01:06
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'
>> 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
Cfdeff3ac35010e4de8f85d954f24f4a?d=identicon&s=25 damphyr (Guest)
on 2005-12-08 23:00
(Received via mailing list)
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

www-data wrote:
> There is a description of how this works here:
>>
>>   class Redirector
>>         STDERR.reopen(open(stderr,"w"))
>>         stdout = tout.path
>>       ret = IO::read(stdout), IO::read(stderr), $?.exitstatus
>>
>>
>>regards.
>>
>>-a
>
>
>


--
http://www.braveworld.net/riva
This topic is locked and can not be replied to.