How to overwrite a printed line in the shell with Ruby? - ruby

How would I overwrite the previously printed line in a Unix shell with Ruby?
Say I'd like to output the current time on a shell every second, but instead of stacking down each time string, I'd like to overwrite the previously displayed time.

You can use the \r escape sequence at the end of the line (the next line will overwrite this line). Following your example:
require 'time'
loop do
time = Time.now.to_s + "\r"
print time
$stdout.flush
sleep 1
end

Use the escape sequence \r at the end of the line - it is a carriage return without a line feed.
On most unix terminals this will do what you want: the next line will overwrite the previous line.
You may want to pad the end of your lines with spaces if they are shorter than the previous lines.
Note that this is not Ruby-specific. This trick works in any language!

Here is an example I just wrote up that takes an Array and outputs whitespace if needed. You can uncomment the speed variable to control the speed at runtime. Also remove the other sleep 0.2 The last part in the array must be blank to output the entire array, still working on fixing it.
##speed = ARGV[0]
strArray = [ "First String there are also things here to backspace", "Second Stringhereare other things too ahdafadsf", "Third String", "Forth String", "Fifth String", "Sixth String", " " ]
#array = [ "/", "-", "|", "|", "-", "\\", " "]
def makeNewLine(array)
diff = nil
print array[0], "\r"
for i in (1..array.count - 1)
#sleep #speed.to_f
sleep 0.2
if array[i].length < array[i - 1].length
diff = array[i - 1].length - array[i].length
end
print array[i]
diff.times { print " " } if !diff.nil?
print "\r"
$stdout.flush
end
end
20.times { makeNewLine(strArray) }
#20.times { makeNewLine(array)}

Following this answer for bash, I've made this method:
def overwrite(text, lines_back = 1)
erase_lines = "\033[1A\033[0K" * lines_back
system("echo \"\r#{erase_lines}#{text}\"")
end
which can be used like this:
def print_some_stuff
print("Only\n")
sleep(1)
overwrite("one")
sleep(1)
overwrite("line")
sleep(1)
overwrite("multiple\nlines")
sleep(1)
overwrite("this\ntime", 2)
end

You can use
Ruby module curses, which was part of the Ruby standard library
Cursor Movement
puts "Old line"
puts "\e[1A\e[Knew line"
See also Overwrite last line on terminal:

Related

Could gets be a loop condition?

Wanted to make a loop asking the user for input each time and break the loop as soon as the input is empty.
lines << line while line = gets.chomp
The code above fails to break the loop. Using the irb and putting in nothing showed that the condition doesn't return a nil:
irb(main):001:0> line = gets.chomp
=> ""
Is there a way to get it work?
The problem that in you sample while loop will break when line is null, but gets.chomp will return empty string when empty line is given.
Simplest solution to use loop with explicit break
lines = []
loop do
line = gets.chomp
break if line.empty?
lines << line
end
If you would use ActiveSupport library(included with Rails) you can do one liner with presence method
lines << line while line = gets.chomp.presence

Remove " " from line Ruby

I have a loop which read lines from text file :
text = File.open("file.txt").read
text.gsub!(/\n\r?/, "\n", )
text.each_line do |line|
# do something with line
end
And in each iteration I get line with " " in the end of line : "word ", and I need get just "word"
How fix my problem?
ll = line.clone.sub!(" ", "") - returns nil
You might want to use String#strip or one of the similar methods to remove whitespace. In this example String#rstrip seems to be an option:
text.each_line do |line|
sanitized_line = line.rstrip
# ...
end
line.gsub!(/\s+/, "") - fixed my problem.

Ruby doesn't read carriage return (\r) in output? [duplicate]

This question already has an answer here:
Ruby outputting to the same line as the previous output
(1 answer)
Closed 8 years ago.
in ruby, how do I make my output (via puts method) on one line, as opposed to line after line, and my console being flooded with output. Basically I want the output to continuously update on one line, and keep writing over the last output. I tried doing a '\r' character at the end of the string, but ruby just ignores it and keeps printing the output of my while loop line after line:
i=0
while i<90
puts "#{i} matt lao \r"
i+=1
end
I just want one continuously updated line. Thank you.
puts will always print a new line at the end, so it's doing your carriage return but then a new line after that. Use print instead.
90.times { |i| print "#{i} matt lao \r" }
To see it's actually doing the right thing, you can stick in a sleep:
90.times { |i| print "#{i} matt lao \r"; sleep 0.01 }
You could use print without any carriage return which will work just fine.
like this
2.1.1 :016 > 0.upto(4){|i| print "#{i} "}
0 1 2 3 4 => 0
puts automatically appends a new line whereas print doesn't.
You need to use print instead of puts.
For example:
90.times do |i|
print "#{i} matt lao \r"; sleep 0.02
end

Why doesn't puts() print in a single line?

This is a piece of code:
def add(a, b)
a + b;
end
print "Tell number 1 : "
number1 = gets.to_f
print "and number 2 : "
number2 = gets.to_f
puts "#{number1}+#{number2} = " , add(number1, number2) , "\n"`
When I run it, my results are spread over several lines:
C:\Users\Filip>ruby ext1.rb
Tell number 1 : 2
and number 2 : 3
3.0+3.0 =
5.0
C:\Users\Filip>
Why doesn't puts() print in a single line, and how can keep the output on one line?
gets() includes the newline. Replace it with gets.strip. (Update: You updated your code, so if you're happy working with floats, this is no longer relevant.)
puts() adds a newline for each argument that doesn't already end in a newline. Your code is equivalent to:
print "#{number1}+#{number2} = ", "\n",
add(number1, number2) , "\n",
"\n"
You can replace puts with print:
print "#{number1}+#{number2} = " , add(number1, number2) , "\n"`
or better:
puts "#{number1}+#{number2} = #{add(number1, number2)}"
Because puts prints a string followed by a newline. If you do not want newlines, use print instead.
Puts adds a newline to the end of the output. Print does not. Try print.
http://ruby-doc.org/core-2.0/IO.html#method-i-puts
You might also want to replace gets with gets.chomp.
puts "After entering something, you can see the the 'New Line': "
a = gets
print a
puts "After entering something, you can't see the the 'New Line': "
a = gets.chomp
print a

Concatenating strings with variables with Ruby

I am writing a test script that opens a file with a list of URLs without the "www" and "com".
I am trying to read each line and put the line into the URL. I then check to see if it redirects or even exists.
My problem is when I read the line from the file and assign it to a variable. I then do a compare with what's in the URL after loading and what I initially put in there, but it seems to be adding a return after my variable.
Basically it is always saying redirect because it puts "http://www.line\n.com/".
How can I get rid of the "\n"?
counter = 1
file = File.new("Data/activeSites.txt", "r")
while (line = file.gets)
puts "#{counter}: #{line}"
counter = counter + 1
browser.goto("http://www." + line + ".com/")
if browser.url == "http://www." + line + ".com/"
puts "Did not redirect"
else
puts ("Redirected to " + browser.url)
#puts ("http://www." + line + ".com/")
puts "http://www.#{line}.com/"
end
Basically it is always saying redirect because it puts http://www.line and then return .com/
How can I get rid of the return?
Short answer: strip
"text\n ".strip # => "text"
Long answer:
Your code isn't very ruby-like and could be refactored.
# Using File#each_line, the line will not include the newline character
# Adding with_index will add the current line index as a parameter to the block
File.open("Data/activeSites.txt").each_line.with_index do |line, counter|
puts "#{counter + 1}: #{line}"
# You're using this 3 times already, let's make it a variable
url = "http://#{line}.com"
browser.goto(url)
if browser.url == url
puts "Did not redirect"
else
puts ("Redirected to " + browser.url)
puts url
end
end
That's because your lines are terminated by a newline. You need to strip it off:
while (line = file.gets)
line.strip!
puts "#{counter}: #{line}"
# ...
Note that there are better ways of iterating over the lines in a file:
File.foreach("Data/activeSites.txt") do |line|
# ...
end
This is your code after reindenting it to the "Ruby way":
counter = 1
file = File.new("Data/activeSites.txt", "r")
while (line = file.gets)
puts "#{counter}: #{line}"
counter = counter + 1
browser.goto("http://www." + line + ".com/")
if browser.url == "http://www." + line + ".com/"
puts "Did not redirect"
else
puts ("Redirected to " + browser.url)
#puts ("http://www." + line + ".com/")
puts "http://www.#{line}.com/"
end
It's not correct because it's missing a closing end for the while. But, it's also not dealing with file IO correctly.
This is how I'd write it:
File.foreach("Data/activeSites.txt") do |line|
puts "#{ $. }: #{ line }"
browser.goto("http://www.#{ line }.com/")
if browser.url == "http://www.#{ line }.com/"
puts "Did not redirect"
else
puts "Redirected to #{ browser.url }"
puts "http://www.#{ line }.com/"
end
end
File.foreach is a method inherited from IO. If you read the file correctly you don't need to strip or chomp, because Ruby will handle it correctly when IO.foreach reads the line.
Every time IO reads a line it increments the $. global, which is short-hand for $INPUT_LINE_NUMBER. There's no need to keep a counter. Using:
require 'english'
will enable the verbose names. See the English docs for more information.

Resources