Ruby: In-place Progress Output with Net::SCP
I really like the Net::SSH and Net::SCP gems, they are pure ruby implementations of the SSH and SCP protocols. I’ve been playing around with these gems lately and I noticed an interesting tidbit in Net::SCP’s docs:
To receive progress reports for the current operation, just pass a block to upload or download (or one of their variants):
scp.upload!("/path/to/local", "/path/to/remote") do |ch, name, sent, total|
puts "#{name}: #{sent}/#{total}"
end
I thought this was pretty cool, but when I went to implement it, I received the following output:

This is pretty ugly, especially when we compare it to CLI tools like wget, which does in-place updating of their output.
So how do we go about achieving the same user experience when writing a CLI tool with Net::SCP? Thanks to this handy StackOverflow post, we can achieve this feature with the help of the carriage return character (\r). After some code tweaking:
name_old = ""
scp.upload!(local, remote, {:ssh => ssh_args}) do |ch, name, sent, total|
if name_old == name
STDOUT.write "\r#{name}: #{sent}/#{total}"
else
STDOUT.write "\n\r#{name}: #{sent}/#{total}"
end
name_old = name
end
I was able to get the clean output I needed:
