Reputation: 307
For a project of mine I essentially want to be able to pass a command to a Node.js script and have it execute it and record the output line by line. This is what I have right now:
var child_process = require('child_process');
var child_spawn = child_process.spawn('ruby', ['test.rb']);
child_spawn.stdout.on('data', function(data) {
console.log('stdout: ' + data);
});
Now when I tail -f the system log this works as I would except but when I test it with a trivial ruby script I wrote it recieves all the output at once as if it were buffered?
The script in question is:
puts "hello"
sleep(1)
puts "there"
sleep(1)
puts "my"
sleep(1)
puts "name"
sleep(1)
puts "is"
sleep(1)
puts "james"
When I run this on it's own it works as I'm sure you can imagine, printing out one line at a time with a second gap in between.
On the node docs (http://nodejs.org/api/child_process.html) I saw this:
(Note that some programs use line-buffered I/O internally. That doesn't affect node.js but it means data you send to the child process is not immediately consumed.)
Is that what is happening here and is there a way around it?
Upvotes: 1
Views: 1651
Reputation: 307
vkurchatkin's (https://stackoverflow.com/a/20978696/483271) answer correctly explains the reason for why this happening.
How I actually got around this however was by making use of this https://github.com/chjj/pty.js/ (available on npm), it allows emulation of a terminal so Ruby doesn't buffer it's output and seems to have a compatible API to child_process from what I've seen so far.
Upvotes: 0
Reputation: 13570
That's exactly what happens. Check this:
puts "hello"
STDOUT.flush
sleep(1)
puts "there"
STDOUT.flush
sleep(1)
puts "my"
STDOUT.flush
sleep(1)
puts "name"
STDOUT.flush
sleep(1)
puts "is"
STDOUT.flush
sleep(1)
puts "james"
STDOUT.flush
I assume that ruby detects if stout is not a tty, and if so buffers all the output and flushes when the script exits. Putting STDOUT.sync = true
seems to fix this issue.
Upvotes: 1