Capture output

What should I do in order to capture output to a string ???

You can’t, in the way that you showed. You must use IO.popen as I said
before.

Im no expert on this… I don’t agree… earlier with help of the
Redirector class it almost worked, except for a few glitches.
I hope that some of you rubists has a nicer solution than Redirector ?

Yes, I know that IO.popen can be used for capturing output from
child processes. But I really want to use “system” and “backquote” :slight_smile:

The problem is this: you are forking a child process, which inherits
stdin/stdout/stderr. It then writes to them using Unix write() calls, to
file descriptors 1 (stdout) and 2 (stderr).

Now, you can redirect fds 1/2 to a file before forking, in which case the
child will write to that file. But you cannot redirect those fds to a Ruby
object, because the Unix write() syscall does not call Ruby!

Im no expert on this either… thus im asking :slight_smile:
VIM can execute a child process and capture its output.
How does other applications do this redirection ?
I cannot believe that this is NOT possible with ruby ???

[snip good technical description]

But in general, I think it’s the right thing to let stderr do its job, of
giving an out-of-band error reporting channel.

I want to capture all output like VIM or Emacs… I want to
do the same… I don’t agree with you here :wink:

···

On Wed, 07 May 2003 20:31:39 +0900, Brian Candler wrote:

On Wed, May 07, 2003 at 06:55:54PM +0900, Simon Strandgaard wrote:


Simon Strandgaard

Hi,

A bit more testing reveals that this seems to be a problem of the mswin
version:

IO multiplexing on pipes doesn’t work on Windows. It’s a known
restriction.

I noticed also, that closing STDERR or $stderr does seem to close STDOUT,
too. Is this intended behavior or is it a known bug?

Neither. Could you detail? This worked for me, at least.

$ ruby16-mswin -e ‘STDERR.close; puts “hello”’
hello

···

At Thu, 8 May 2003 16:49:22 +0900, Robert Klemme wrote:


Nobu Nakada

What is the recommended procedure for using named pipes in Ruby. Does one
use kernel.open and then attach to the pipes using File.open, or do you use
popen…

Been experimenting with it, and producing lots of lockups, but no pipe
action.

Thanks,

Mark

Hi,

···

At Wed, 7 May 2003 19:36:33 +0900, Simon Strandgaard wrote:

Capturing output to a File works fine… But not to StringIO, Why ???

StringIO works only in a process, not across processes.

Do you have any suggestions for an alternative to StringIO ?

Fundamentaly, StringIO works in the process’es memory space, so
it’s not accessible from child processes. Use pipe with popen
as Brian mentioned in [ruby-talk:70798], or popen3.


Nobu Nakada

The problem is this: you are forking a child process, which inherits
stdin/stdout/stderr. It then writes to them using Unix write() calls, to
file descriptors 1 (stdout) and 2 (stderr).

Now, you can redirect fds 1/2 to a file before forking, in which case the
child will write to that file. But you cannot redirect those fds to a Ruby
object, because the Unix write() syscall does not call Ruby!

Im no expert on this either… thus im asking :slight_smile:
VIM can execute a child process and capture its output.

Yes: it opens a pipe, forks, and passes one end of the pipe as stdout
(and/or stderr) to the child. In Ruby, that’s IO.popen.

How does other applications do this redirection ?
I cannot believe that this is NOT possible with ruby ???

I think I have answered this several times already!

The only thing is, as far as I know, IO.popen will not attach both stderr
and stdout to the same pipe. You can submit that as a feature request.

Brian.

···

On Wed, May 07, 2003 at 08:16:44PM +0900, Simon Strandgaard wrote:

nobu.nokada@softhome.net schrieb im Newsbeitrag
news:200305081052.h48AqYeR008509@sharui.nakada.kanuma.tochigi.jp…

Hi,

A bit more testing reveals that this seems to be a problem of the
mswin
version:

IO multiplexing on pipes doesn’t work on Windows. It’s a known
restriction.

Ah! Thanks a lot for clearing this! I would have thought that a file
descriptor pointing to a pipe end is the same as a file descriptor
pointing to a terminal or file, but then - it’s windows… sigh

I noticed also, that closing STDERR or $stderr does seem to close
STDOUT,
too. Is this intended behavior or is it a known bug?

Neither. Could you detail? This worked for me, at least.

$ ruby16-mswin -e ‘STDERR.close; puts “hello”’
hello

True for me, too. Apparently I draw the wrong conclusion while
experimenting with pipe redirecting. One of the scripts I was using for
experiments (see attached) did seem to eat STDOUT output when STDERR was
closed. Strange, though.

Kind regards

robert

capture-4.rb (379 Bytes)

···

At Thu, 8 May 2003 16:49:22 +0900, > Robert Klemme wrote:

As far as I know, a named pipe is just opened using File.open as if it
were a file (i.e. no kernel stuff required). This is how it works in Unix
anyway.

Regards,

Brian.

···

On Mon, May 19, 2003 at 06:33:17PM +0900, Mark Firestone wrote:

What is the recommended procedure for using named pipes in Ruby. Does one
use kernel.open and then attach to the pipes using File.open, or do you use
popen…

popen3 looks very interesting… transfering control in a
grand-child-process outputting to somewhere else…
I must admit I don’t quite understand exactly what is going on.
This is propably something like popen3 which I need.

Still… this doesn’t solve my problem.

Story of my problem:
I am developing a programmers-editor for both GUI and TTY.
It has a ruby backend and some C++ frontends.
Its suppose to be extremely customizable: You can load you own
ruby-scripts into the backend.
http://metaeditor.sf.net/

Goal:
Users of the editor should be able to run their favoite
ruby scripts from the within the editor-backend.

Now the problem:
if a User does a “system” or “backquote” call the output will
not be transfered correctly to the execute-buffer.
This will especialy cause problems with a Ncurses-frontend
for the editor.

How can I capture this output ?

···

On Wed, 07 May 2003 20:43:52 +0900, nobu.nokad wrote:

At Wed, 7 May 2003 19:36:33 +0900, > Simon Strandgaard wrote:

Capturing output to a File works fine… But not to StringIO, Why ???

StringIO works only in a process, not across processes.

Do you have any suggestions for an alternative to StringIO ?

Fundamentaly, StringIO works in the process’es memory space, so
it’s not accessible from child processes. Use pipe with popen
as Brian mentioned in [ruby-talk:70798], or popen3.


Simon Strandgaard

How does other applications do this redirection ?

I think I have answered this several times already!

Yes… I think we have a human-communication problem here (broken-pipe)
Im not a native english speaker and im having reduced sight…
and im worried that you don’t have caught my question right :wink:
maybe there is more reasons?

The only thing is, as far as I know, IO.popen will not attach both stderr
and stdout to the same pipe. You can submit that as a feature request.

I have never tried filing a RCR and I have no expert knowledge
about the exact problem… I think its better you do it ?

···

On Wed, 07 May 2003 22:22:27 +0900, Brian Candler wrote:

On Wed, May 07, 2003 at 08:16:44PM +0900, Simon Strandgaard wrote:


Simon Strandgaard

Hi,

True for me, too. Apparently I draw the wrong conclusion while
experimenting with pipe redirecting. One of the scripts I was using for
experiments (see attached) did seem to eat STDOUT output when STDERR was
closed. Strange, though.

  1. you cannot reopen closed stream.

$ ruby -e ‘STDOUT.close;STDOUT.reopen(STDERR)’
-e:1:in `reopen’: closed stream (IOError)
from -e:1

  1. IO#reopen duplicates the file descriptor, so you have to
    close also reopened stream to tell EOF to peer.

puts “Sending message to parent”
STDERR.write “Hi Dad”
+STDERR.close
wr.close

···

At Thu, 8 May 2003 20:50:29 +0900, Robert Klemme wrote:


Nobu Nakada

Ok. Thanks for that. I guess this is going to be trial and error. My
concern is that i am wasting my time trying to fix something that may be
working … and that it could be DOSEMU that isn’t…

I need to find a way to test it with something else… Hmmm…

So, I wonder what IO.pipes does?

Thanks for your help.

Mark

···

At 19:34 19/05/2003 +0900, you wrote:

As far as I know, a named pipe is just opened using File.open as if it
were a file (i.e. no kernel stuff required). This is how it works in Unix
anyway.

Regards,

Brian.

Well, it’s not a feature that I want, so I don’t think I’m the right person
to do that.

Regards,

Brian.

···

On Wed, May 07, 2003 at 09:57:28PM +0900, Simon Strandgaard wrote:

The only thing is, as far as I know, IO.popen will not attach both stderr
and stdout to the same pipe. You can submit that as a feature request.

I have never tried filing a RCR and I have no expert knowledge
about the exact problem… I think its better you do it ?

From /usr/local/lib/ruby/1.6/open3.rb:

Usage:

require “open3”

···

On Wed, May 07, 2003 at 09:37:12PM +0900, Simon Strandgaard wrote:

popen3 looks very interesting… transfering control in a
grand-child-process outputting to somewhere else..
I must admit I don’t quite understand exactly what is going on.
This is propably something like popen3 which I need.

in, out, err = Open3.popen3(‘nroff -man’)

or

include Open3

in, out, err = popen3(‘nroff -man’)

It should do the job, but note that it’s your responsibility to read from
‘out’ and ‘err’ simultaneously, which means having a thread for each (and
another one for supplying data on ‘in’ if you wish to do that as well; if
not, call in.close straight away)

Regards,

Brian.

What about something like this. You start a ruby process in C++ in its own
pseudo-tty, so that all output (stdout and stderr) of ruby and ruby’s
subprocesses is sent to the tty. To execute snippets of ruby code, simply
write them to the ruby interpreter. And there is always one ruby interpreter,
no child.

Example of codes:
Start the ruby interpreter
int mtty; /* Master tty descriptor */
FILE *fd;
switch(forkpty(&mtty, NULL, NULL, NULL)) {
case -1:
exit(1);

case 0:
execl("/usr/bin/ruby", "ruby");
break;

default:
fd = fdopen(mtty, "r+");

}

Send command to the interpreter:
fputs(fd, “system("echo Hello")\n”);

Read output:
char buff[1024];
fgets(buff, 1024, fd); /* buff == “Hello” */

Hope that helps,
Guillaume.

NB: thist should work on Linux. For linking, you need -lutil.

···

On Wednesday 07 May 2003 08:57 am, you wrote:

On Wed, 07 May 2003 22:22:27 +0900, Brian Candler wrote:

On Wed, May 07, 2003 at 08:16:44PM +0900, Simon Strandgaard wrote:

How does other applications do this redirection ?

I think I have answered this several times already!

Yes… I think we have a human-communication problem here (broken-pipe)
Im not a native english speaker and im having reduced sight…
and im worried that you don’t have caught my question right :wink:
maybe there is more reasons?

The only thing is, as far as I know, IO.popen will not attach both stderr
and stdout to the same pipe. You can submit that as a feature request.

I have never tried filing a RCR and I have no expert knowledge
about the exact problem… I think its better you do it ?

nobu.nokada@softhome.net schrieb im Newsbeitrag
news:200305081214.h48CExeR010459@sharui.nakada.kanuma.tochigi.jp…

Hi,

True for me, too. Apparently I draw the wrong conclusion while
experimenting with pipe redirecting. One of the scripts I was using
for
experiments (see attached) did seem to eat STDOUT output when STDERR
was
closed. Strange, though.

  1. you cannot reopen closed stream.

$ ruby -e ‘STDOUT.close;STDOUT.reopen(STDERR)’
-e:1:in `reopen’: closed stream (IOError)
from -e:1

I inserted the close before reopen only for experimental reasons. But
thanks anyway!

  1. IO#reopen duplicates the file descriptor, so you have to
    close also reopened stream to tell EOF to peer.

puts “Sending message to parent”
STDERR.write “Hi Dad”
+STDERR.close
wr.close

Aha! Thanks again!

Regards

robert
···

At Thu, 8 May 2003 20:50:29 +0900, > Robert Klemme wrote:

Hi,

···

In message “Re: IO.pipe + thread = hangs (was: Re: capture output)” on 03/05/08, nobu.nokada@softhome.net nobu.nokada@softhome.net writes:

  1. you cannot reopen closed stream.

$ ruby -e ‘STDOUT.close;STDOUT.reopen(STDERR)’
-e:1:in `reopen’: closed stream (IOError)
from -e:1

It should be possible to reopen closed IO. I will fix.

						matz.

Ok. Thanks for that. I guess this is going to be trial and error. My
concern is that i am wasting my time trying to fix something that may be
working … and that it could be DOSEMU that isn’t…

I need to find a way to test it with something else… Hmmm…

So, I wonder what IO.pipes does?

A named pipe is something you create in the filesystem with ‘mkfifo’. One
process can open it for writing, and another process open it for reading.

$ mkfifo zer
$ ls -l zer
prw-r–r-- 1 brian brian 0 May 20 11:30 zer
^

`this shows it’s a named pipe

I don’t think DOS has any concept of named pipes.

There is no “IO.pipes” that I am aware of, but there is “IO.pipe”. This
creates an unnamed pipe with two endpoints, already open for reading and
writing - see “man 2 pipe” for the Unix view of this, and
http://www.rubycentral.com/book/ref_c_io.html#IO.pipe
for the Ruby view.

You could then have two Ruby threads, one reading and one writing to the
same pipe, or you could fork another process (in the latter case
IO.popen(“-”) is simpler since it does the fork as well as the pipe
creation)

I don’t think ‘fork’ will work in DOS, but Ruby threads should be fine:

rd, wr = IO.pipe
Thread.new do
wr.print “Hello world!”
wr.close
end
result = rd.read
rd.close
puts “I got: #{result.inspect}”

If that doesn’t solve your problem, then perhaps you can describe what it is
you’re trying to do?

Regards,

Brian.

···

On Tue, May 20, 2003 at 04:18:13PM +0900, Mark Firestone wrote:

[snip popen talk]

Sorry… I never thought it would be that hard to explain
my problem :slight_smile:

I embed ruby into C++. The “void main” is located in the frontend.
Right now everything is running in the same process.

User supplyed ruby-code is executed in the same process…
its NOT executed as a child-process, thus popen3 is not possible.
The only thing which is possible right now is the flawed Redirector class
technique.

Setting up the redirection will occur within c++!

My setup routine looks like this

void lib_begin() {
if(lib_running)
return;

// initialize ruby itself
ruby_init();
ruby_init_loadpath();
ruby_script("embed");

// setup our own environment
objects = new RUBY_CPP::Objects;
Redirect::RubyInit();

/* ---------------------------
       todo: setup capture here!
--------------------------- */

RUBY_CPP::Require("test");

lib_running = true;
cout << "aeditorlib: started (" << 
	(use_swig ? "with" : "no") << "-swig)" << endl;

}

···

On Wed, 07 May 2003 23:31:06 +0900, Brian Candler wrote:


Simon Strandgaard

Is this a feature I want ?
I don’t know enough about IO.popen so I cannot tell.

Could this be useful?

···

On Wed, 07 May 2003 23:27:24 +0900, Brian Candler wrote:

On Wed, May 07, 2003 at 09:57:28PM +0900, Simon Strandgaard wrote:

The only thing is, as far as I know, IO.popen will not attach both stderr
and stdout to the same pipe. You can submit that as a feature request.

I have never tried filing a RCR and I have no expert knowledge
about the exact problem… I think its better you do it ?

Well, it’s not a feature that I want, so I don’t think I’m the right person
to do that.


Simon Strandgaard

[snip example]

Im embedding ruby into c++ and sharing a bunch of classes between
ruby and c++.

I don’t want to execute the ruby binary everytime I do a
function call in c++. Besides I don’t want to write that
wrapper which marshals all input/output to a temporary file.
Well… I think it would work. But it would definitly be be way
to slow to be really usable.

···

On Thu, 08 May 2003 04:23:39 +0900, Guillaume Marcais wrote:

What about something like this. You start a ruby process in C++ in its own
pseudo-tty, so that all output (stdout and stderr) of ruby and ruby’s
subprocesses is sent to the tty. To execute snippets of ruby code, simply
write them to the ruby interpreter. And there is always one ruby interpreter,
no child.

Simon Strandgaard