Execute commands and print their output - ruby

Is there a way in ruby to execute a command line utility and have its output displayed in real time, something like myrubyscript rspec, where myrubyscript runs rspec and immediately prints output as it receives it from rspec?
Currently, if I invoke rspec with backticks or system, I don't see the rspec output immediately. Rather, it prints at the end.
Preferably, I want the solution to have block form, so that I run code before and after I exec the passed argument.

Use Open3.popen3.
require "open3"
Open3.popen3...

Related

How can I preserve output color when executing a process in Ruby?

I'm using a helper script to execute rspec tests.
command = "rake spec #{path} #{scope}"
output = `#{command}`
puts output
This works fine, except that I lose all the colors from the rake rspec output. The appropriate ANSI codes do not appear to be contained within the output string.
How can I execute a process so that it returns output which includes the text color?
Kernel.exec() gets me the solution I want (colored rspec output), but it does so by replacing my ruby script process with the rspec process. That means I can't do anything with the output or run anything after the rspec call.
That's acceptable in my particular situation, but less than ideal as a general solution. So I'd like a better answer if available.
RSpec will disable colour if it is not writing to a tty (i.e. the console).
In case of RSpec you can force colouring by rspec --tty or via rake by rake spec SPEC_OPTS=' --tty'.
See also Ruby popen3 and ANSI colour
However this solution is still specific to Rspec. I'd be interested to hear a general one.
Turns out it's possible to run commands in a pseudo terminal via the PTY module in order to preserve a user facing terminal-like behaviour. Credits go to the creator of the tty-command gem (see this issue) who implemented this behaviour in his gem:
require 'tty-command'
cmd = TTY::Command.new(pty: true)
cmd.run('rake', 'rspec')
Keep in mind that using a pseudo terminal may have unwanted side effects, such as certain git commands using a pager which will essentially cause commands to hang. So introducing the functionality might be a breaking change.
If you don't want to replace your ruby process with that command, use Kernel.system() or Kernel.spawn() instead of a Kernel.exec(). Both of them execute your command in a subshell, system waits for the subprocess to finish, spawn returns its pid and you have to wait by yourself using Process.wait pid.
command = "rake spec #{path} #{scope}"
system(command)
or
command = "rake spec #{path} #{scope}"
pid = spawn(command)
# Some other stuff here
Process.wait pid

Ruby, pry: Can I add something to the command `pry example.rb` so pry automatically goes interactive when it finishes executing the script?

Pry goes into interactive mode if it encounters an exception (eg if you just put an undefined variable 'x' at the end of the script).
(Also if, inside the script itself you require 'pry' and put binding.pry at the point you want to go interactive at.)
But I'm wondering: Is there's some kind of flag/option/argument thingy that I can add to the pry example.rb command when I enter it at the command prompt, so it will go interactive when it reaches the end of executing any example.rb script, regardless of what's inside? (Assuming no exceptions before the end, of course.)
(This would obviously be especially useful for use with editors that you can run external programs from like Notepad++, see this and this.)
Not yet, but file an issue and i'll add it :)

How can I make RSpec output to console when run as a command %x[rspec] from Ruby script?

I have a class with an instance method that runs RSpec using the %x[] notation:
class TestRunner
def run_rspec
# do stuff
%x[rspec spec -c -f documentation]
# do more stuff
end
end
When I do this:
> tr = TestRunner.new
> tr.run_rspec
The documentation (group and example names) does not appear in the console.
To contrast, when I run rspec straight from the command line I get this:
$ rspec spec -c -f documentation
a group name
an example
another example
...
I don't want to do this:
puts %x[rspec spec -c -f documentation
Because then the output all spits out in one huge clump at the very end. I want it to run in "real time," with each example showing up as each test is run.
Is there a way, with the setup I have, to get RSpec to announce what it's doing, as it's doing it (as it does when run normally from the command line)?
I've been advised that system() and the other shell methods can be dangerous to use, so I've opted to switch to the even-better approach of using RSpec itself:
RSpec::Core::Runner.run(['spec', '-c', '-f', 'documentation'])
rather than calling it via shell from my Ruby script.
Ruby offers several options for running programs from the command line. I was using %x[], the wrong choice for my use case.
Solution: Use system(), not %x[] -- rspec will write to STDOUT in real-time when I call it with system('rspec spec').
Some background in case it's helpful to anyone who stumbles upon this question:
Consider the differences between Ruby's command-line options:
%x[command] accumulates the result of command and returns it, in one chunk.
exec('command') will output command as command runs, but will replace whatever process called it -- i.e., if you use exec in your Ruby script, your Ruby script won't finish.
system('command') executes command in a subshell, and returns to the calling script.
This is why system was the choice for my script.

Piping stdin to ruby script via `myapp | myscript.rb`

I have an app that runs continuously, dumping output from a server and sending strings to stdout. I want to process this output with a Ruby script. The strings are \n-terminated.
For example, I'm trying to run this on the command line:
myapp.exe | my_script.rb
...with my_script.rb defined as:
while $stdin.gets
puts $_
end
I ultimately am going to process the strings using regexes and display some summary data, but for now I'm just trying to get the basic functionality hooked up. When I run the above, I get the following error:
my_script.rb:1:in `gets': Bad file descriptor (Errno::EBADF)
from my_script.rb:1
I am running this on Windows Server 2003 R2 SP2 and Ruby 1.8.6.
How do I continuously process stdin in a Ruby script? (Continuously as in not processing a file, but running until I kill it.)
EDIT:
I was able to make this work, sort of. There were several problems standing in my way. For one thing, it may be that using Ruby to process the piped-in stdin from another process doesn't work on Windows 2003R2. Another direction, suggested by Adrian below, was to run my script as the parent process and use popen to connect to myapp.exe as a forked child process. Unfortunately, fork isn't implemented in Windows, so this didn't work either.
Finally I was able to download POpen4, a RubyGem that does implement popen on Windows. Using this in combination with Adrian's suggestion, I was able to write this script which does what I really want -- processes the output from myapp.exe:
file: my_script.rb
require 'rubygems'
require 'popen4'
status =
POpen4::popen4("myapp.exe") do |stdout, stderr, stdin, pid|
puts pid
while s = stdout.gets
puts s
end
end
This script echoes the output from myapp.exe, which is exactly what I want.
Try just plain gets, without the $stdin. If that doesn't work, you might have to examine the output of myapp.exe for non-printable characters with another ruby script, using IO.popen.
gets doesn't always use stdin but instead tries to open a file.
See SO.
Try executing your Ruby script by explicitly calling ruby:
myapp.exe | ruby my_script.rb
I've experienced some odd behavior using stdin in Ruby when relying on Windows to invoke the correct program based on the file associations.

Can Ruby access output from shell commands as it appears?

My Ruby script is running a shell command and parsing the output from it. However, it seems the command is first executed and output saved in an array. I would like to be able to access the output lines in real time just as they are printed. I've played around with threads, but haven't got it to work. Any suggestions?
You are looking for pipes. Here is an example:
# This example runs the netstat command via a pipe
# and processes the data in Ruby as it come back
pipe = IO.popen("netstat 3")
while (line = pipe.gets)
print line
print "and"
end
When call methods/functions to run system/shell commands, your interpreter spawns another process to run it and waits for it to finish, then gives you the output.
Even if you use threads, the only thing that you would accomplish is not letting your program to hang while the command is run, but you still won't get the output till its done.
I think you can accomplish that with pipes, but I am not sure how.
#Marcel got it.

Resources