ruby output format - ruby

I have the following code, which works fine. The problem is that I get the following output:
Device ID: SEP1C17D3415659
IP address: 10.2.3.101
I would like to get:
SEP1C17D3415659 10.2.3.101
Thanks for your help
require 'net/telnet'
require '/apps/dateformat'
#tdate = Formatdate.new.mydate
hosts = %w"SW3"
hosts.each do |hostname|
tn = Net::Telnet::new("Host" => "#{hostname}",
"Timeout" => 10000,
"Prompt" => /[$%#>] \z/n)
tn.cmd('String' =>'user' , 'Match'=>/Password:/) { |c| puts c }
tn.cmd('String' =>'password', 'Match'=>/#/) { |c| puts c }
tn.cmd('String' =>'terminal length 0', 'Match'=>/#/) { |c| puts c }
File.open("/agents/#{hostname}-#{#tdate}-agents.txt",'w') do |o|
run=tn.cmd('String' =>'sh cd ne de | inc Device ID: | IP address:', 'Match'=>/#/) { |c| puts c }
run.each_line do |re|
mac = re.match /Device ID: ([\S]+)/
#ip = re.match /([\S]+) address/
ip = re.match /IP address: ([\S]+)/
o.puts mac
o.puts ip
end
end
end

puts automatically prints a new line after each output. Simply put both on the same line.
outputString = mac + " " + ip
o.puts outputString
If you have other output functions available such as print, it will function without putting a newline between the two statements.

You're correctly specify the grouping you want for your regular expression, but you're not using it when printing it out.
Your regular expression is:
mac = re.match /Device ID: ([\S]+)/
and this matches the whole line Device ID: SEP1C17D3415659, putting the part you want (SEP1C17D3415659) into a group so you can get at it later. However you then print it out using
o.puts mac
This gives the whole match, not just the group. What you want is this instead:
o.puts mac[1]
which specifies just the group.
Also, as Cody says, puts adds a newline on each call. If you want both matches to print on the same line try something like:
o.print "#{mac[1]} #{ip[1]}\n"
instead.
Edit:
I'm not familiar with net/telnet or the command you're running, but it looks like you're running a certain command, then filtering for certain lines and then printing some info from those lines. If this is the case, then any lines that don't match will give you nil for mac and ip so you'll get "undefind method []" on those lines.
If this is the case you can simply use:
o.print "#{mac[1]} #{ip[1]}\n" unless mac.nil?
You might find it worth while to restructure your code slightly to better express what you're doing, by combining the two regular expressions into one. Without knowing the structure of the actual lines I can't create the real expression you'll need, but it would look something like this:
run.each_line do |line|
match = line.match /^Device ID: ([\S]+), IP address: ([\S]+)$/ #these are the lines we want
next unless match #skip lines we don't want
o.print "#{match[1]} #{match[2]}\n" #print the details we're interested in
end

Related

How to print all linux users with Puppet and ruby?

I want to create a facter that returns all users.
Facter.add("sysusers") do
setcode do
File.readlines('/etc/passwd').each do |line|
line.match(/^[^:]+/)[0]
end
end
end
Then in my .pp file I have this:
$users = inline_template("<%= scope.lookupvar('sysusers') %>")
$users.each |String $user| {
notify { "$user":}
}
This should work but the facter returns just one letter at a time.
So notify { "$user":} just prints:
Notify[r]
Notify[o]
And then it craches because the next letter is also "o" (two o`s in "root" and root is the first user stated in /etc/passwd).
So how can I print all the users?
EDIT
With the edit to:
Facter.add("sysusers") do
setcode do
File.readlines('/etc/passwd').each do |line|
line.match(/^[^:]+/).to_s
end
end
end
Then the output is:
root#mymachine]# facter sysusers
[
"root:x:0:0:root:/root:/bin/bash
",
"bin:x:1:1:bin:/bin:/usr/bin/nologin
",
"daemon:x:2:2:daemon:/:/usr/bin/nologin
...
...
So it still does not seem to work as expeced.
This is the match you want.
line.match(/^[^:]+/).to_s
When you add [0], it is taking the first character from the string that is the user name.
EDIT
File.readlines('/etc/passwd').collect do |line|
line.match(/^[^:]+/).to_s
end
That will collect an array which to be returned in your setcode.
Parsing /etc/passwd is a clunky approach to your problem.
It's cleaner to use the Etc module
require 'etc'
result = []
Etc.passwd { |user| result << user.name }
result
Use the following ruby code, which reads and prints the user names from /etc/passwd file.
IO.readlines("/etc/passwd").each do |val|
user = val.split(":").first
puts user
end

Ruby retrieve data from file after specific label

How can I get specific data from a file in ruby? I want to get some 10. ip addresses from a file set up like this...
Whatever: xathun
ip_address: 10.2.232.6
etc: aouoeu
more: snthuh
I want to push the ip addresses into an array.
I can pull 10. addresses out of text. I was hoping for a more accurate way to do it as in only the data after the 'ip_address:' label in case there is unwanted matching data.
s_text = File.open("test.txt",'r').read
ip_addresses = s_text.scan(/\d+.\d+.\d+.\d+/)
puts ip_addresses.inspect #=> ["10.2.232.6"]
Here's a simple enough solution.
open('<textfile path>') { |f| puts f.grep(/10\./) }
If the file is setup like that throughout you can do:
arr = []
File.open("text").each_line do |line|
parts = line.split(":")
arr << parts[1].strip if parts[0] == "ip_address"
end
adding to array as you go through once, one line at a time:
ip_data.txt
Whatever: xathun
ip_address: 10.2.232.6
etc: aouoeu
more: snthuh
Whatever: badone
ip_address: 66.8.103.3
etc: huh
more: noooo
Whatever: blah
ip_address: 10.9.244.13
etc: hello
more: goodbye
code
found_tens = []
File.open('ip_data.txt') {|f|
f.each {|line|
line = line.chomp
next if line.empty?
found_tens << $1 if line =~ /^ip_address:\s+(10\.\d+\.\d+\.\d+)/
}
}
p found_tens #["10.2.232.6", "10.9.244.13"]

How do I make an array of arrays out of a CSV?

I have a CSV file that looks like this:
Jenny, jenny#example.com ,
Ricky, ricky#example.com ,
Josefina josefina#example.com ,
I'm trying to get this output:
users_array = [
['Jenny', 'jenny#example.com'], ['Ricky', 'ricky#example.com'], ['Josefina', 'josefina#example.com']
]
I've tried this:
users_array = Array.new
file = File.new('csv_file.csv', 'r')
file.each_line("\n") do |row|
puts row + "\n"
columns = row.split(",")
users_array.push columns
puts users_array
end
Unfortunately, in Terminal, this returns:
Jenny
jenny#example.com
Ricky
ricky#example.com
Josefina
josefina#example.com
Which I don't think will work for this:
users_array.each_with_index do |user|
add_page.form_with(:id => 'new_user') do |f|
f.field_with(:id => "user_email").value = user[0]
f.field_with(:id => "user_name").value = user[1]
end.click_button
end
What do I need to change? Or is there a better way to solve this problem?
Ruby's standard library has a CSV class with a similar api to File but contains a number of useful methods for working with tabular data. To get the output you want, all you need to do is this:
require 'csv'
users_array = CSV.read('csv_file.csv')
PS - I think you are getting the output you expected with your file parsing as well, but maybe you're thrown off by how it is printing to the terminal. puts behaves differently with arrays, printing each member object on a new line instead of as a single array. If you want to view it as an array, use puts my_array.inspect.
Assuming that your CSV file actually has a comma between the name and email address on the third line:
require 'csv'
users_array = []
CSV.foreach('csv_file.csv') do |row|
users_array.push row.delete_if(&:nil?).map(&:strip)
end
users_array
# => [["Jenny", "jenny#example.com"],
# ["Ricky", "ricky#example.com"],
# ["Josefina", "josefina#example.com"]]
There may be a simpler way, but what I'm doing there is discarding the nil field created by the trailing comma and stripping the spaces around the email addresses.

Taking multiple lines from a file and creating hash

I'm taking a file and reading in it's contents and creating a hash based on newlines. I've been able to make a hash based on the contents of each line, but how can I create a hash based on the content of everything before the next blank newline? Below is what I have so far.
Input:
Title 49th parallel
URL http://artsweb.bham.ac.uk/
Domain artsweb.bham.ac.uk
Title ABAA booknet
URL http://abaa.org/
Domain abaa.org
Code:
File.readlines('A.cfg').each do |line|
unless line.strip.empty?
hash = Hash[*line.strip.split("\t")]
puts hash
end
puts "\n" if line.strip.empty?
end
Outputs:
{"Title"=>"49th parallel"}
{"URL"=>"http://artsweb.bham.ac.uk/"}
{"Domain"=>"artsweb.bham.ac.uk"}
{"Title"=>"ABAA booknet"}
{"URL"=>"http://abaa.org/"}
{"Domain"=>"abaa.org"}
Desired Output:
{"Title"=>"49th parallel", "URL"=>"http://artsweb.bham.ac.uk/", "Domain"=>"artsweb.bham.ac.uk"}
{"Title"=>"ABAA booknet", "URL"=>"http://abaa.org/", "Domain"=>"abaa.org"}
Modifying your existing code, this does what you want:
hash = {}
File.readlines('A.cfg').each do |line|
if line.strip.empty?
puts hash if not hash.empty?
hash = {}
puts "\n"
else
hash.merge!(Hash[*line.strip.split("\t")])
end
end
puts hash
You can likely simplify that depending on what you're actually doing with the data.
open('A.cfg', &:read)
.strip.split(/#$/{2,}/)
.map{|s| Hash[s.scan(/^(\S+)\s+(\S+)/)]}
gives
[
{
"Title" => "49th",
"URL" => "http://artsweb.bham.ac.uk/",
"Domain" => "artsweb.bham.ac.uk"
},
{
"Title" => "ABAA",
"URL" => "http://abaa.org/",
"Domain" => "abaa.org"
}
]
read the whole content of the file using read:
contents = ""
File.open('A.cfg').do |file|
contents = file.read
end
And then split the contents on two newline characters:
contents.split("\n\n")
And lastly, create a function pretty similar to what you already have to parse those chunks.
Please note that if you are working on windows it may happen that you need to split on a different sequence because of the carriage return character.

Working with hashes in ruby on rails

My apologizes if this has been covered before; I searched and searched but I did not find an answer...
I have the following hash:
input = '{"names":[{"name":"a1","id":1},{"name":"b2","id":2}]}'
I'd like to extract and display the values- one per line. When I run it from rails console, I get the correct results:
>> r1 = ActiveSupport::JSON.decode(input)
=> {"names"=>[{"name"=>"a1", "id"=>1}, {"name"=>"b2", "id"=>2}]}
>> r1["names"].each do |x|
?> puts "#{x["name"]}"
>> end
a1
b2
=> [{"name"=>"a1", "id"=>1}, {"name"=>"b2", "id"=>2}]
THe question is how do I replicate this behavior in my rails application? I tried the following method, but only one value is return in the browser:
module PageHelper
def testcall()
input = '{"names":[{"name":"a1","id":1},{"name":"b2","id":2}]}'
r1 = ActiveSupport::JSON.decode(input)
r1["names"].each do |a|
return "Name: #{a["name"]}\n"
end
end
TIA!
returning terminates the loop after the first element. Try appending the output to a string (including newlines \n in-between) in the loop, and then return that string after the loop.
As #Irfy said, this is happening because of return statement. Following code works,
module PageHelper
def testcall()
input = '{"names":[{"name":"a1","id":1},{"name":"b2","id":2}]}'
r1 = ActiveSupport::JSON.decode(input)
r1["names"].map{|hash| hash["name"]}
end
end

Resources