getting stdout and stderr for system calls on windows

Discussion in 'Ruby' started by Damphyr, Nov 23, 2005.

  1. Damphyr

    Damphyr Guest

    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.
     
    Damphyr, Nov 23, 2005
    #1
    1. Advertising

  2. Damphyr

    Ara.T.Howard Guest

    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", :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
    ===============================================================================
     
    Ara.T.Howard, Nov 23, 2005
    #2
    1. Advertising

  3. Damphyr

    Damphyr Guest

    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 wrote:
    > 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", :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.
     
    Damphyr, Dec 8, 2005
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. horos22
    Replies:
    15
    Views:
    1,637
  2. Ian Hobson
    Replies:
    0
    Views:
    700
    Ian Hobson
    Sep 6, 2010
  3. Ian
    Replies:
    0
    Views:
    411
  4. Patrick Bennett
    Replies:
    7
    Views:
    120
    Ara.T.Howard
    Feb 2, 2004
  5. Marv
    Replies:
    3
    Views:
    193
    Leslie Hazelton
    Feb 3, 2004
Loading...

Share This Page