Ruby - How do you scan this text content? - ruby

I want an output like this: ["# foo\n\n1234\n\n", "# bar\n\nk23j4k2j4\nk23j4kj4\n\n", "# baz\n\nk2k2k2\n\n"] with scan method from following text content.
content = '
# foo
1234
# bar
k23j4k2j4
k23j4kj4
# baz
k2k2k2
'
I tried the following code. But it didn't work as I think.
p content.scan(/^#.*/m)
# => ["# foo\n\n1234\n\n# bar\n\nk23j4k2j4\nk23j4kj4\n\n# baz\n\nk2k2k2\n\n"]
How do you solve this?
note: Alternatively You can use split or other methods instead of scan.

. matchs all strings including #.
You have to exclude it.
content.scan(/^#[^#]*/m)
# => ["# foo\n\n1234\n\n", "# bar\n\nk23j4k2j4\nk23j4kj4\n\n", "# baz\n\nk2k2k2\n\n"]

try
content.scan(/#[^#]*/)
it matches # and anything else until you find # again
=> ["# foo\n\n1234\n\n", "# bar\n\nk23j4k2j4\nk23j4kj4\n\n", "# baz\n\nk2k2k2\n\n"]

Related

convert space separated string in bash to list in ruby

I have a space separated string of IPs that I am exporting to a Vagrantfile which I want to iterate over.
export IP="10.10.10.10 10.10.10.11"
I want to perform an operation on this so it becomes a list in the vagrantfile to iterate over.
["10.10.10.10", "10.10.10.11"]
What is the way to do this?
Try figure it out yourself in bash:
$ export IP="10.10.10.10 10.10.10.11"
$ irb # interactive ruby
> puts ENV['IP'] # make sure IP is not nil
10.10.10.10 10.10.10.11 # output
> IPs = ENV['IP'].split
> puts IPs
Vagrantfile is a Ruby script, so you can use ENV['IP'].split in it
The following should be robust. You would not need to worry about padding by space characters at the beginning or the end of the string, or about irregular sequences of space characters.
"10.10.10.10 10.10.10.11".scan(/\S+/)
# => ["10.10.10.10", "10.10.10.11"]
You can just use Split directly as from the examples,
" now's the time".split
=> ["now's", "the", "time"]
>> "10.10.10.10 10.10.10.11".split
=> ["10.10.10.10", "10.10.10.11"]
>> "10.10.10.10 10.10.10.11".split
=> ["10.10.10.10", "10.10.10.11"]
>> " 10.10.10.10 10.10.10.11".split
=> ["10.10.10.10", "10.10.10.11"]
>> "".split
=> []
Read the Docs here
To include variables in vagrant file, Refer this
Use split in a simple way
"10.10.10.10 10.10.10.11".split(' ')
=> ["10.10.10.10", "10.10.10.11"]

How to get input from a user with ARGV in Ruby to read a file?

I'm trying to read the content of a file (myfile.txt) through ARGV in Ruby. Here is my code:
filename = ARGV.first
puts "Here's your file #{filename}:"
print txt.read
What I have to do to pass the name of the file to ARGV?
Solution
With a ruby script called read_file.rb :
# read_file.rb
# example :
# ruby read_file.rb some_file.txt
filename = ARGV.first
puts "Here's your file #{filename}:"
print File.read(filename)
You can call :
ruby read_file.rb myfile.txt
Your code
print txt.read
txt isn't defined. If you meant filename, filename is a String which contains a filename. It's not a File object, so you cannot call filename.read directly.
Best use
ARGF.read
Notice the spelling with an ...F
ARGF is a stream of either all files named in the arguments, or standard input if no file has been named. This is best practice for scripts and allows your program to be used with a unix pipe.
cat filename | ruby script.rb
ruby script.rb filename
Will both work and do the same if you use ARGF.
Try the following.
file = ARGV.first
file_name_with_extn = File.basename file # => "abc.mp4"
file_extn = File.extname file # => ".mp4"
file_name = File.basename file, extn # => "abc"
file_path = File.dirname file # => "/path/"

Custom fact with home directorys as domains for puppet

I'm trying to generate a custom fact called domains.
the idea is to list all the directories within /home but remove some default directory's such as centos, ec2-user, myadmin.
I'm using bash as I don't know ruby. so far my script outputs the list into a txt file which it then cats the answer for factors. but it is treated as one long answer and not multiple like an array?
My script is as follows:
#!/bin/bash
ls -m /home/ | sed -e 's/, /,/g' | tr -d '\n' > /tmp/domains.txt
cat /tmp/domains.txt | awk '{gsub("it_support,", "");print}'| awk '{gsub("ec2-user,", "");print}'| awk '{gsub("myadmin,", "");print}'| awk '{gsub("nginx", "");print}'| awk '{gsub("lost+found,", "");print}' > /tmp/domains1.txt
echo "domains={$(cat /tmp/domains1.txt)}"
exit
Foremans sees my domains as
facts.domains = "{domain1,domain2,domain3,domain4,lost+found,}"
I also need to remove lost+found, some how.
Any help or advice would be appreciated
Kevin
I'm also not familiar with ruby, but I have an idea for some workaround:
Please look at the following example about returning an array of network interfaces. Now to create domain_array fact use the following code:
Facter.add(:domain_array) do
setcode do
domains = Facter.value(:domains)
domain_array = domains.split(',')
domain_array
end
end
You can put a parser function to do this. Parser functions go inside:
modules/<modulename>/lib/puppet/parser/functions/getdomain.rb
Note: Parser function will compile only in the puppet master. See below for a custom fact that will run on the agent.
getdomain.rb can contain something like the following for your purpose:
module Puppet::Parser::Functions
newfunction(:getdomain, :type => :rvalue) do |args|
dnames=Array.new
Dir.foreach("/home/") do |d|
# Avoid listing directories starts with . or ..
if !d.start_with?('.') then
# You can put more names inside the [...] that you want to avoid
dnames.push(d) unless ['lost+found','centos'].include?(d)
end
end
domainlist=dnames.join(',')
return domainlist
end
end
You can call it from a manifest and assign to a variable:
$myhomedomains=getdomain()
$myhomedomains should return something similar to this : user1,user2,user3
.......
For a custom fact with similar code. You can put it in :
modules/<modulename>/lib/facter/getdomain.rb
Content of getdomain.rb :
Facter.add(:getdomain) do
setcode do
dnames=Array.new
Dir.foreach("/home/") do |d|
# Avoid listing directories starts with . or ..
if !d.start_with?('.') then
# You can put more names inside the [...] that you want to avoid
dnames.push(d) unless ['lost+found','centos'].include?(d)
end
end
getdomain=dnames.join(',')
getdomain
end
end
You can call the getdomain fact in any manifest, for example, calling it from the same module's init.pp :
notify { "$::getdomain" : }
will result in something similar :
Notice: /Stage[main]/Testmodule/Notify[user1,user2,user3]

mixing file.write and system calls that write to same file

I have code that invokes two system commands that write to a file and I need to add something else from my code in between these calls:
File.open('test.txt', 'w') {|f|
`echo 1 > #{f.path}`
f.write '2'
`echo 3 >> #{f.path}`
}
as the result the file contains just
2
3
the first line is missing. I am sure there is a simple solution, but I cannot find it.
You are opening the file in "write" mode which is clobbering the first echo. Instead use 'append' mode. Additionally, you're not flushing after you write "2" so it'll be out of order when you read it back. Remember, f.write doesn't append a newline, so you probably need that too.
irb(main):020:0> File.open('asdf', 'a') do |f|
irb(main):021:1* `echo 1 > asdf`
irb(main):022:1> f.write("2\n") and f.flush
irb(main):023:1> `echo 3 >> asdf`
irb(main):024:1> end
=> ""
irb(main):025:0> File.read('asdf')
=> "1\n2\n3\n"
irb(main):026:0> puts File.read('asdf')
1
2
3
The File.open(name, 'a') is the important part. It means append to this file instead of overwriting it. See http://www.ruby-doc.org/core-2.0/IO.html#method-c-new and What are the Ruby File.open modes and options? for descriptions of file open modes.
If it's important to delete any existing file, the first echo will implicitly take care of that (since it's a single >). Or you can do it in ruby explicitly:
File.delete('asdf') if File.exists?('asdf')
to answer my own question:
File.open('test.txt', 'w') {|f|
`echo 11 > #{f.path}`
f.seek(0, IO::SEEK_END)
f.write "2\n"
f.flush
`echo 33 >> #{f.path}`
}

How to gsub slash "/" with back slash and slash "\/" in ruby

I try to modify "/foo/bar/dir" to "\/foo\/bar\/dir" by ruby gsub command.
I test it in irb the result is
x = "/foo/bar/dir"
x.gsub("/","\/")
=> "/foo/bar/dir"
x.gsub("/","\\/")
=> "\\/foo\\/bar\\/dir"
Is it possible to replace "/" with "/" by gsub ?
Source of problems:
I try to execute "string in command line" and "real_path" is my variable
real_path = "/home/me/www/idata"
path = real_path.gsub("/","\\/")
=> \\/home\\/me\\/www\\/idata
# But what I expect is \/home\/me\/www\/idata
run "sed 's/SHARE_PATH/#{path}/g' #{path}/config/sphinx.yml > #{path}/config/sphinx.tmp.yml"
result from "run" command is
"sh -c 'sed '\''s/SHARE_PATH/\\/home\\/me\\/www\\/idata\\/shared/g .... "
I need is only one back slash like
"sh -c 'sed '\''s/SHARE_PATH/\/home\/me\/www\/idata\/shared/g .... "
"run" is command from Capistrano
my solution is
use single quote instead of double quote like this
path = real_path.gsub("/",'\/')
You have written:
x = "/foo/bar/dir"
x.gsub("/","\\/")
=> "\\/foo\\/bar\\/dir"
so You did what You had asked before. x.gsub("/","\\/") in fact evaluates to "\/foo\/bar\/dir" but irb prints return value of inspect method instead of to_s.
Edit: Did You mean
real_path.gsub("/","\/")
istead of
real_path.gsub("\/","\/")
Anyway the output is correct - You changed / with \/ so You have
"sh -c 'sed '\''s/SHARE_PATH/\/home\/me\/www\/idata\/shared/g'\'' .... "`
instead of
`"sh -c 'sed '\''s/SHARE_PATH//home/me/www/idata/shared/g'\'' .... "`
and result is different from irb's result (notice the lack of doubled backslash).
For path manipulation I recommend using File.join (documentation)
By the way: why are You modifying the path this way? (1)
Edit2: Why are You asking about changing "/" to "/" but write the following line?
path = real_path.gsub("\/","\\/")
What are You trying to achieve? And what is Your answer to question (1) ?
Edit3:
Here We go:
>> real_path = "/foo/bar/dir"
=> "/foo/bar/dir"
>> path = real_path.gsub("/", "\\/")
=> "\\/foo\\/bar\\/dir"
>> puts "sed 's/SHARE_PATH/#{path}/g' #{path}/config/sphinx.yml > #{path}/config/sphinx.tmp.yml"
sed 's/SHARE_PATH/\/foo\/bar\/dir/g' \/foo\/bar\/dir/config/sphinx.yml > \/foo\/bar\/dir/config/sphinx.tmp.yml
=> nil
>>
but I do not understand why You need backslash in a path?
Yes
irb(main):028:0> (t = x.gsub("/", "\\/")) && nil
=> nil
irb(main):029:0> t
=> "\\/foo\\/bar\\/dir"
irb(main):030:0> puts t
\/foo\/bar\/dir
=> nil
Your first example actually did what you wanted, but the .inspect method that irb is using is escaping backslashes, so it looked like there were extras. If you had used puts you would have seen the real result.

Resources