Tee in ruby while catching status

Hi all,

I’m wondering how I would write a program such as ‘tee’ in ruby while
being able to catch the exit status of the program teed.

ls /sldjclsc | tee.rb out
echo $?

would actually echo 1

is this possible? it would require that the exit status get’s passed in
the pipe. Does it?

My problem is really this…
I’m trying to write a makefile in such a way that I get all the results
of a run in the makefile at the same time as logging the output.
However, since I’m using tee, the make file doesn’t exit with an error
if the call I’m making returns with an error as ‘tee’ supresses it.

Suggestions are welcome.

db

···


Mar 25 Triangle Shirt Waist Fire, 1911
Mar 25 Greek Independence Day in Cyprus
Mar 25 Lady Day (a.k.a. the Feast of the Annunciation)
Mar 25 Maryland Day in Maryland
Mar 25 National Holiday in Greece
Mar 25 Aretha Franklin is born in Detroit, 1943

Hi all,

I’m wondering how I would write a program such as ‘tee’ in ruby while
being able to catch the exit status of the program teed.

ls /sldjclsc | tee.rb out
echo $?

would actually echo 1

is this possible? it would require that the exit status get’s passed in
the pipe. Does it?

Unfortunately for you, no. The exit status is returned to the parent process
only, as it is returned via the wait() function used by the parent to reap
its child. In this case, the ‘parent process’ is the shell which starts two
children (ls and tee) with a pipe between them. The shell choses the exit
code of the second child to return as the final exit code of the pipeline.

My problem is really this…
I’m trying to write a makefile in such a way that I get all the results
of a run in the makefile at the same time as logging the output.
However, since I’m using tee, the make file doesn’t exit with an error
if the call I’m making returns with an error as ‘tee’ supresses it.

Suggestions are welcome.

Personally I do:

make >make.out 2>&1

i.e. capture the output of ‘make’ itself rather than the individual actions
in the makefile.

You could write a different version of ‘tee’ which spawns the process of
interest (ls) itself, and passes back the right return code: you’d run it as

teepee out ls /sldjclsc

See IO.popen and $? for the tools you’d need to write that in Ruby.

If you want a more flexible solution, albeit one which is under rapid
development, then you might want to look at ‘rake’ which was announced here
in the last few days…

Regards,

Brian.

···

On Wed, Mar 26, 2003 at 08:28:56AM +0900, Daniel Bretoi wrote:

Personally I do:

make >make.out 2>&1

I need to see the output to the screen while doing it. :confused:

You could write a different version of ‘tee’ which spawns the process of
interest (ls) itself, and passes back the right return code: you’d run it as

teepee out ls /sldjclsc

I thought of that. What in ruby would enable me to print output while
it’s happening? A systemcall will let me see it. I can’ twait for the
process to finish before seing output as some of the executions can take
hours, and there is useful output in the meantime.

db

maybe something like this:

def doit(command)
IO.popen(“command”,“r”) do |io|
io.each { |line| puts line }
end

return status

$?
end

robert

“Daniel Bretoi” lists@debonair.net schrieb im Newsbeitrag
news:20030326165818.GC99575@zone.syracuse.net

Personally I do:

make >make.out 2>&1

I need to see the output to the screen while doing it. :confused:

You could write a different version of ‘tee’ which spawns the process
of
interest (ls) itself, and passes back the right return code: you’d run
it as

···

teepee out ls /sldjclsc

I thought of that. What in ruby would enable me to print output while
it’s happening? A systemcall will let me see it. I can’ twait for the
process to finish before seing output as some of the executions can take
hours, and there is useful output in the meantime.

db

I usually stick this in the background, then run ‘tail -f make.out’ when I’m
interested in seeing how it’s progressing. But you could just pipe make’s
output via tee.

Regards,

Brian.

···

On Thu, Mar 27, 2003 at 01:25:37AM +0900, Daniel Bretoi wrote:

Personally I do:

make >make.out 2>&1

I need to see the output to the screen while doing it. :confused:

Thanks for your help so far guys.

Is this possible to do yet be able to get the stderr as well?

I’m trying to use Open3, but am having trobules to get the output as
it’s occurring.

db

···

On Thu, Mar 27, 2003 at 02:48:58AM +0900, Robert Klemme wrote:

maybe something like this:

def doit(command)
IO.popen(“command”,“r”) do |io|
io.each { |line| puts line }
end

return status

$?
end

robert

“Daniel Bretoi” lists@debonair.net schrieb im Newsbeitrag
news:20030326165818.GC99575@zone.syracuse.net

Personally I do:

make >make.out 2>&1

I need to see the output to the screen while doing it. :confused:

You could write a different version of ‘tee’ which spawns the process
of
interest (ls) itself, and passes back the right return code: you’d run
it as

teepee out ls /sldjclsc

I thought of that. What in ruby would enable me to print output while
it’s happening? A systemcall will let me see it. I can’ twait for the
process to finish before seing output as some of the executions can take
hours, and there is useful output in the meantime.

db


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971

Hi,

I managed to sort it out :slight_smile:

db

···

On Thu, Mar 27, 2003 at 07:06:49AM +0900, Daniel Bretoi wrote:

Thanks for your help so far guys.

Is this possible to do yet be able to get the stderr as well?

I’m trying to use Open3, but am having trobules to get the output as
it’s occurring.

db

On Thu, Mar 27, 2003 at 02:48:58AM +0900, Robert Klemme wrote:

maybe something like this:

def doit(command)
IO.popen(“command”,“r”) do |io|
io.each { |line| puts line }
end

return status

$?
end

robert

“Daniel Bretoi” lists@debonair.net schrieb im Newsbeitrag
news:20030326165818.GC99575@zone.syracuse.net

Personally I do:

make >make.out 2>&1

I need to see the output to the screen while doing it. :confused:

You could write a different version of ‘tee’ which spawns the process
of
interest (ls) itself, and passes back the right return code: you’d run
it as

teepee out ls /sldjclsc

I thought of that. What in ruby would enable me to print output while
it’s happening? A systemcall will let me see it. I can’ twait for the
process to finish before seing output as some of the executions can take
hours, and there is useful output in the meantime.

db


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971

I take it back, I didn’t.
This is what I have now:

require ‘open3’
def doit(command)
logfile = command.shift
Open3.popen3(command.join(’ ')) { |inp,out,err|
fh = File.open(logfile,“w”)
out.each { |line| puts line; fh.print line }
err.each { |line| puts line; fh.print line }
}
$? >> 8
end

however, as you can see, all the stderr stuff will be always shown at
the end. Is there no way to mix stdout and stderr the way it would
naturally be displaye don the screen at runtime?

db

···

On Thu, Mar 27, 2003 at 07:12:24AM +0900, Daniel Bretoi wrote:

Hi,

I managed to sort it out :slight_smile:

db

On Thu, Mar 27, 2003 at 07:06:49AM +0900, Daniel Bretoi wrote:

Thanks for your help so far guys.

Is this possible to do yet be able to get the stderr as well?

I’m trying to use Open3, but am having trobules to get the output as
it’s occurring.

db

On Thu, Mar 27, 2003 at 02:48:58AM +0900, Robert Klemme wrote:

maybe something like this:

def doit(command)
IO.popen(“command”,“r”) do |io|
io.each { |line| puts line }
end

return status

$?
end

robert

“Daniel Bretoi” lists@debonair.net schrieb im Newsbeitrag
news:20030326165818.GC99575@zone.syracuse.net

Personally I do:

make >make.out 2>&1

I need to see the output to the screen while doing it. :confused:

You could write a different version of ‘tee’ which spawns the process
of
interest (ls) itself, and passes back the right return code: you’d run
it as

teepee out ls /sldjclsc

I thought of that. What in ruby would enable me to print output while
it’s happening? A systemcall will let me see it. I can’ twait for the
process to finish before seing output as some of the executions can take
hours, and there is useful output in the meantime.

db


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971

Guess I’m talking to myself here, but I seem to have solved the problem
with threads. I guess this is possibly useful for anyone else dealing
with this in the future, so I’m posting my solution.

Open3.popen3(command.join(’ ')) { |inp,out,err|
fh = File.open(logfile,“w”)

  threads <<  Thread.new(out) { |out|
     out.each { |line| puts line; fh.print line }
  }     
  threads <<  Thread.new(err) { |err|
     err.each { |line| puts line; fh.print line }
  }        
  threads.each { |t| t.join }

}

db

···

On Thu, Mar 27, 2003 at 07:22:00AM +0900, Daniel Bretoi wrote:

I take it back, I didn’t.
This is what I have now:

require ‘open3’
def doit(command)
logfile = command.shift
Open3.popen3(command.join(’ ')) { |inp,out,err|
fh = File.open(logfile,“w”)
out.each { |line| puts line; fh.print line }
err.each { |line| puts line; fh.print line }
}
$? >> 8
end

however, as you can see, all the stderr stuff will be always shown at
the end. Is there no way to mix stdout and stderr the way it would
naturally be displaye don the screen at runtime?

db

On Thu, Mar 27, 2003 at 07:12:24AM +0900, Daniel Bretoi wrote:

Hi,

I managed to sort it out :slight_smile:

db

On Thu, Mar 27, 2003 at 07:06:49AM +0900, Daniel Bretoi wrote:

Thanks for your help so far guys.

Is this possible to do yet be able to get the stderr as well?

I’m trying to use Open3, but am having trobules to get the output as
it’s occurring.

db

On Thu, Mar 27, 2003 at 02:48:58AM +0900, Robert Klemme wrote:

maybe something like this:

def doit(command)
IO.popen(“command”,“r”) do |io|
io.each { |line| puts line }
end

return status

$?
end

robert

“Daniel Bretoi” lists@debonair.net schrieb im Newsbeitrag
news:20030326165818.GC99575@zone.syracuse.net

Personally I do:

make >make.out 2>&1

I need to see the output to the screen while doing it. :confused:

You could write a different version of ‘tee’ which spawns the process
of
interest (ls) itself, and passes back the right return code: you’d run
it as

teepee out ls /sldjclsc

I thought of that. What in ruby would enable me to print output while
it’s happening? A systemcall will let me see it. I can’ twait for the
process to finish before seing output as some of the executions can take
hours, and there is useful output in the meantime.

db


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971


Mar 26 Benjamin Thompson born, 1753, Count Rumford; physicist
Mar 26 David Packard died, 1996; age of 83
Mar 26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
Mar 26 Independence Day in Bangladesh
Mar 26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
Mar 26 Emerson, Lake, and Palmer record “Pictures at an Exhibition” live, 1971

I think using IO::select / Kernel::select may help:

--------------------------------------------------------- Kernel::select
select( readArray [, writeArray [errorArray [timeout]]] ) →
anArray or nil

···

On Wednesday 26 March 2003 05:22 pm, Daniel Bretoi wrote:

I take it back, I didn’t.
This is what I have now:

require ‘open3’
def doit(command)
logfile = command.shift
Open3.popen3(command.join(’ ')) { |inp,out,err|
fh = File.open(logfile,“w”)
out.each { |line| puts line; fh.print line }
err.each { |line| puts line; fh.print line }
}
$? >> 8
end

however, as you can see, all the stderr stuff will be always shown at
the end. Is there no way to mix stdout and stderr the way it would
naturally be displaye don the screen at runtime?

db


 Performs a low-level select call, which waits for data to become
 available from input/output devices. The first three parameters are
 arrays of IO objects or nil. The last is a timeout in seconds,
 which should be an Integer or a Float. The call waits for data to
 become available for any of the IO objects in readArray, for
 buffers to have cleared sufficiently to enable writing to any of
 the devices in writeArray, or for an error to occur on the devices
 in errorArray. If one or more of these conditions are met, the call
 returns a three-element array containing arrays of the IO objects
 that were ready. Otherwise, if there is no change in status for
 timeout seconds, the call returns nil. If all parameters are nil,
 the current thread sleeps forever.
    select( [$stdin], nil, nil, 1.5 )   #=> [[#<IO:0x4019202c>], [], []]

AFAIK using this you can ‘multiplex’ data from several IO objects in order.

Hope this helps!


author: Bruce R. Williams
url: http://codedbliss.com
irc: { nick: iusris, channel: ruby-lang, server: irc.freenode.net }
quote: >
It does not require a majority to prevail, but rather an irate,
tireless minority keen to set brush fires in people’s minds.’
– Samuel Adams