Ruby : Pass array in command line argument - ruby-on-rails

I want to pass array in argument in such a way suppose process.rb is my script and the argument will be like:
i/p
process.rb server{1..4}
process.rb prodserver{2..3}
process.rb devserver3
The process.rb should accept all the inputs and parse it in such a way that when I print the variable which holds the arguments give me below result.
o/p
puts arguments
server1
server2
server3
server4
or
prodserver2
prodserver3
or
devserver3
I have a shell script which does the same:
for i in "$#"
do
echo $i
done
i/p
server{1..4}
o/p
server1server2server3server4
I wanted to have the same logic in the ruby.
Since I am a new bie in ruby I am not able to find the same on google.
Please let me know how I can get this output or any article about the related to my question

The list is expanded by the shell before it ever hits your script. In other words, both your shell script and your Ruby script do not receive a single argument server{1..4} but rather they receive four arguments server1 server2 server3 server4, before they even start interpreting the arguments themselves.
You can simply just iterate over those, there is no need to parse the {1..4} shell expansion syntax yourself because you will never see it! It is already parsed and expanded by the shell before the shell passes off the arguments to your script.
ruby -e 'p ARGV' -- server{1..4}
# ["server1", "server2", "server3", "server4"]

#!ruby
ARGV.each do |i|
puts i
end
Basically ARGV holds all arguments passed to program, and puts prints string with new line added (the same as echo without -n flag in shell).

Command-line arguments in Ruby end up in ARGV. You can duplicate your shell script's functionality by iterating over that:
ARGV.each do |a|
puts a
end

If I understand you correctly you want to expand the range that comes in string form from your argument ARGV[0] ? My samples use a string to demonstrate it workd, replace the string by ARGV[0]
def expand_range arg
string, range = arg.split("{") #split arg in string part and rangestring part
if range #if a range is given
# parse the rangestring to an range by splitting the string on ..
# and splash this array to both its elements, convert them to integer
# and transform into a real range
# and enumerate each number in the range
Range.new(*range.split("..").map(&:to_i)).each do |val|
#concatenate the string part with the number
p "#{string}#{val}"
end
else #else just pass the string
p string
end
end
expand_range 'server{1..4}'
# "server1"
# "server2"
# "server3"
# "server4"
expand_range 'devserver3'
#"devserver3"
Personally I would return an array and print that instead of printing in the method itself, that would be more multifunctional.

Related

Calling a command inside a ruby script

Is there a way to call a command like last inside a ruby script? I can use %x to call commands like ls and ls -l within a script, but would that be acceptable for the complex and constantly expanding log information provided by the last command?
Here's an example, to retrieve user name, ip, startup and duration :
%x(last -i).each_line do |line|
line.chomp! # Removes newline
break if line.empty? # last is done
# 3 possibilities to extract information :
user, *other_columns = line.split(' ') # 1. Use split
start = Time.parse(line[39,16]) # 2. Use known position of a column
ip = line[22,17].strip
if line =~/\((\d+):(\d+)\)/ # 3. Use a regex
duration = $1.to_i*60+$2.to_i
else
duration = nil
end
info={user: user, ip: ip, start: start, duration: duration}
#TODO: Check that user isn't "reboot"
puts info
end
# {:user=>"ricou", :ip=>"0.0.0.0", :start=>2016-11-01 21:29:00 +0100, :duration=>141}
# {:user=>"ricou", :ip=>"0.0.0.0", :start=>2016-11-01 15:21:00 +0100, :duration=>57}
Which information do you need exactly?

run a remote ruby script (pass parameters as well) using ssh

I want to connect to a remote host and run a ruby script on the remote host. Following is the code that I am using -
ssh = Net::SSH.start(host, user)
args = "some argument" //can be any data type, list, string, anything
results = conn.exec!('ruby runfile.rb args')
It's not passing args to the file in this case. I have also tried using double quotes instead of single quotes. How do I send the parameters as well?
the name of the connection variable must be consistent (ssh ≠ conn).
You need to send the content of args instead of the string "args":
Double quotes are needed for the #{...} syntax to work. Or use 'ruby runfile.rb ' + args if you prefer.
Use # instead of // to comment Ruby code.
Use .shellescape to harden against unwanted (accidental or malicious) effects in the remote shell.
This code does work:
require 'net/ssh'
require 'shellwords'
ssh = Net::SSH.start(host, user)
args = "some argument".shellescape #can be any data type, list, string, anything
results = ssh.exec!("ruby runfile.rb #{args}")
puts results

Assign bash output to variable in .lua script

I would like to assign output of a bash command to a variable in .lua script. Is it possible?
For instance, something similar to:
var = `ps uax | grep myprocess`
Yes, you need to use io.popen for this.
io.popen (prog [, mode])
Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w").
This function is system dependent and is not available on all platforms.
Also see How to execute an external command?.
io.popen calls a command but returns a file object so you can read the output of the command, if the second argument is 'r', but you can also pass input to a command with a second argument of 'w'. Unfortunately, you don't get a io.popen2, and you don't get the return code.

What does #{$$} inside a double quoted string in Ruby on Rails ?

I have a doubt concerning #{$$} inside a double quoted string, in concrete I have this string:
"#{command}#{$$}#{(Time.now.to_f * 1000).to_i}"
If I execute "#{$$}" in console I get an integer number but I would like to read an explanation to this.
Thank you !!
$$ is the interpreter's process ID.
Ruby has quite a few global variables you can use, see here.
That would be the global process ID.
If you're asking what the #{...} syntax means, that prints the variable inside the braces. So if it would work like this..
command = "print"
puts "cmd: #{command}" #=> cmd: print

Does popen() add a line feed (\n) at the end of the result?

I've wrote a small function that returns the result of executing a command.
function axsh(cmd)
local fullCmd=cmd:lower()
local f,err=io.popen(fullCmd,"r")
if not f then
return nil,"Could not create the process '"..fullCmd.."' \nError:"..err
end
return f:read("*all")
end
s=axsh("echo hi")
--print all bytes
print(s:byte(1,s:len()))
The output always has a \n at the end no matter what is the command:
104 105 10
Edit: it happens not only for my own binary command line application but also for almost all OS commands: Windows: "dir", "ipconfig", "echo"... Linux: "ls", "pwd", "ls"...
But when I run the command separately (i.e. windows command prompt) there is no trailing line feed. I don't need it, so need to remove the last character before returning the result.
Question: does this line feed always exist in the result of popen()? I can't find any reference to this behavior in the documentation.
No. io.popen just returns whatever string the command produces. You use echo as command, which happens to put a newline after the string ( this is what makes the command prompt appear on the next line, instead of just after the output).
You can test it by using trying this:
s=axsh([[lua -e "io.write([=[hi]=])"]])
return string.byte(s,1,-1)
which does not end the output with a newline.

Resources