The code below does not print the output of tail -f
. Why? How can I make it work?
#myApp.rb
`ls` #works fine
`tail -f filename` #does not work. why?
Backticks (``) call a system program and return its output. As opposed to the first approach, the command is not provided through a string, but by putting it inside a backticks pair.
Ruby command is a free and open source programming language; it is flexible and is feature rich. As the name suggests, ruby indeed is a jewel language which comes at a very low entry cost. Its plug and play capability and also easily readable syntax makes it very user-friendly.
By using the follow option -f
on tail
the executed command will not immediately terminate.
-f, --follow[={name|descriptor}]
output appended data as the file grows;
The idea of using backticks (or the %x
shortcut), as opposed to using system('...')
is that these statements return the output of the executed commands. This way you could store the result in a variable:
dir_content = `ls`
tail -f
spawns another process, this process keeps on writing to standard output without terminating. Hence, your statement is never finished. Without finishing the statement, a value cannot be returned. If you want to watch and output of a growing file, see the solution to the question:
Watch/read a growing log file.
Alternatively, you could run the command through system
like so:
system('tail -f filename')
What is the difference here? Instead of returning the outpout of the command, it will return true (command run successfully), false (unsuccessful) or nil (command execution failed). Due to the fact, that the output of the command is not redirected to the return statement running tail -f
it will print the content to standard output.
If you are fine with getting the results to standard output you can simply put it into a Thread block. This way the growing content of filename
is written to standard output and you can continue to execute other Ruby code.
Thread.new { system('tail -f filename') }
If you want to have complete control, capture the output in order to store it for retrieval at another point of your script then have a look at the answer to the following question which describes such an approach:
Continuously read from STDOUT of external process in Ruby
It is based on the PTY module which creates and manages pseudo terminals. Basically you can spawn another terminal through this module. The code could then look like so:
require 'pty'
cmd = "tail -f filename"
begin
PTY.spawn(cmd) do |stdin, stdout, pid|
begin
# Do something with the output here: just printing to demonstrate it
stdin.each { |line| print line }
rescue Errno::EIO
puts "Errno:EIO error, but this probably just means " +
"that the process has finished giving output"
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
Finally, there is also a socket approach. Open a socket in Bash or by using socat
, pipe the output of tail -f
to the socket and read in Ruby from the socket.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With