Redirecting stdin for 3. party program

OS: Debian Lenny
Ruby version: 1.8.7.72-3lenny1

==Code==

stdin_read,stdin_write=IO.pipe
pid=fork
if !pid
#$stdin.reopen("/home/admin/.bashrc")
stdin_write.close
$stdin.reopen(stdin_read)

a=gets
puts "ruby child: got '#{a}'"
system("echo bash; mawk '{print \"bash child: got \"$0;exit}'")
exit!

end

stdin_read.close
sleep 1
stdin_write.puts “word1”
sleep 1
stdin_write.puts “word2”
sleep 1
puts “parent: before wait”
Process.wait(pid)
puts “parent: after wait”

==/Code==

=Expected result:=

ruby child: got 'ruby word1

bash
bash child: got 'ruby word2

parent: before wait
parent: after wait

=Actual result:=
ruby child: got 'word1

bash
parent: before wait

->after the line ‘parent: before wait’ has been printed, the program
hangs.

It gets even more interesting if I comment out all the pipe related
stuff and instead redirect $stdin of the child to a file (the line
'$stdin.reopen("/home/admin/.bashrc"):
-I still only get output for ‘ruby child’, none for ‘bash child’ -
however it finishes instead of hanging. Perhaps ruby buffers more stdin
than the single ‘gets’ returns? Multiple ‘gets’ do work correctly.
-If I comment out the ‘gets’, it works! So the subshell started by
‘system’ DOES get the redirected stdin…

=Program that works=
pid=fork
if !pid
$stdin.reopen("/home/admin/.bashrc")

exec("echo bash; mawk '{print \"bash child: got \"$0;exit}'")
exit!

end

puts “parent: before wait”
Process.wait(pid)
puts “parent: after wait”

=Output=
bash
bash child: got # ~/.bashrc: executed by bash(1) for non-login shells.
parent: before wait
parent: after wait

So: What is going wrong when redirecting it to a pipe?
I tried playing around with Kernel.select and replacing system with
exec, but neither changed the result in the least.
I also looked through the implementation of popen4, but can’t spot
anything done differently there. Maybe I’ve already looked at my own
code for to long to spot something obvious though.

So please: Can anyone provide me with a good hint?

One small addendum: I’m not actually interested in reading in something
via ‘gets’ before launching the external command, I only included it for
demonstration purposes.
What I am hoping to get to work is something like the second test case,
just with stdin coming from a pipe instead of a file.

On 6/3/10, Thomas S. [email protected] wrote:

$stdin.reopen(stdin_read)

sleep 1
ruby child: got 'ruby word1
bash
parent: before wait

->after the line ‘parent: before wait’ has been printed, the program
hangs.

I’ve deliberately forgotten all the awk I ever knew, so I modified
your program to use ruby where you had mawk, and it appears to work. I
trust that I have correctly translated the intention of your original
mawk script… Basically, I replaced the system line with:
system(“echo bash; ruby -e ‘print "bash child: got
"+readline;exit’”)

And I see this output:
ruby child: got 'word1

bash
bash child: got word2
parent: before wait
parent: after wait

With your original mawk line, I see the same behavior you do. I’d
suspect a buffering problem, but inserting a flush after puts of word2
doesn’t change anything.

However, when I close the handle stdin_write after writing word2, it
does work, even with mawk. Perhaps mawk is waiting for its stdin to
close before it does anything?

Thank you thank you thank you :slight_smile:

Buffering by mawk simply wasn’t something that crossed my mind at all.
With your ruby line it walks flawlessly.

For anyone interested: mawk needs the Option “-W interactive” do process
input as it arrives…

And I dumbly and persistently searched for the problem on the ruby
side…

Thanks again - solved!

2010/6/3 Thomas S. [email protected]:

Thank you thank you thank you :slight_smile:

Buffering by mawk simply wasn’t something that crossed my mind at all.
With your ruby line it walks flawlessly.

For anyone interested: mawk needs the Option “-W interactive” do process
input as it arrives…

And I dumbly and persistently searched for the problem on the ruby
side…

Thomas, why do you use IO.pipe and fork instead of IO.popen or
Open3.popen3?

Kind regards

robert