The cool thing about programming languages like Ruby is that they’re very conducive to one-liners. You can use them to generate bash statements that you can then pipe back to bash. `ls | ruby -nle 'puts "mv #{$_} #{$_.gsub(/_/, ".")}"' | bash` is a pattern I use all the time, for example. Easy way of generating complex bash statements without having to bother with the bash man page.
Do you need to pipe the ruby output to bash? Ruby could just run the mv directly by wrapping in backticks instead of quotes.
ls | while read filename; do mv "$filename" "$(echo "$filename" | sed "s/_/./g")" || break; done
I think there's a variable expansion syntax that does replacement, but I haven't learned it so I use sed.
I find that piping to a while loop is often simpler and more flexible than something like you've written, but maybe not in this specific case with the weird string replacement syntax. However, mine doesn't have a command injection vulnerability (that I know of).
A real scripting language can also do this easily:
for f in os.listdir("."): os.rename(f, f.replace("_","."))
Sometimes I'm tempted to make Python my shell. The fewer different syntaxes you need to learn for the same basic operations, the better!