I have the following code:
#!/usr/bin/env ruby
require 'yaml'
require 'json'
require 'getoptlong'
DEFAULT_CONF_FILE = 'conf.yaml'
opts = GetoptLong.new(
[ '--asn', '-a', GetoptLong::OPTIONAL_ARGUMENT ],
[ '--modify', '-m', GetoptLong::OPTIONAL_ARGUMENT ]
)
config_file = ARGV[0]
if config_file.to_s.empty?
config_file = DEFAULT_CONF_FILE
end
opts.each do |opt, arg|
case opt
when '--asn'
write_asn_database(arg,config_file)
when '--modify'
generate_modify_conf_file(arg,config_file)
end
end
This code generates some json files according to the given YAML configuration file. And what I am trying to do is:
If in the command line is given a conf file, the program will use that given file;
If not, it will use the default file.
Something like:
Example 1 (with a conf file):
$ ./my_script.rb new_conf_file.yaml -a
Example 2 (without conf file):
$ ./my_script.rb -a
The first example works, the second example gives me the following error:
No such file or directory # rb_sysopen - -a (Errno::ENOENT)
And it makes sense because the program assumes that the option -a is a file.
I'm new to Ruby and I never used the command line to run scripts.
OK, I would post it here. Please do not do this, since it’s just ugly:
config_file = ARGV[0]
unless File.exist?(config_file)
config_file = DEFAULT_CONF_FILE
end
From the very first paragraph of GetoptLong documentation:
The empty option -- (two minus symbols) is used to end option processing. This can be particularly important if options have optional arguments.
Use your code by calling a script as:
# ⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓
./my_script.rb -a -- new_conf_file.yaml
Also, one should put the opts reading part before dealing with ARGV explicitly.
And no, with GetoptLong it is impossible to parse the command line you provided properly.
Related
I want to call Ruby function from command line with array as an argument.
Script name is test.rb
In below code Environments are like test,dev,uat.', am passing as ['test','dev','uat']
I have tried as below:
ruby -r "./test.rb" -e "start_services '['dev','test','uat']','developer','welcome123'"
def start_services(environments,node_user_name,node_password)
environments.each do |env|
puts env
end
puts node_user_name
puts node_password
end
Output:
-e:1: syntax error, unexpected tIDENTIFIER, expecting end-of-input start_services '['dev','test','uat']','developer',' ^
You clearly want to pass an array as the first parameter into start_services method, so you should do it like this:
$ ruby -r "./test.rb" -e "start_services ['dev','test','uat'],'developer','welcome123'"
# output:
dev
test
uat
developer
welcome123
What you've been trying so far was attempt to pass '[\'dev\',\'test\',\'uat\']' string, which was malformed, because you didn't escape ' characters.
Don't pass your credentials as arguments, any user on your system would be able to see them.
Instead, you could save them as environment variables or in a config file.
if ARGV.size == 0
puts "Here's how to launch this script : ruby #{__FILE__} env_name1 env_name2 ..."
exit
end
# Define those environment variables before launching the script.
# Alternative : write credentials in a json or yml file.
node_username = ENV["NODE_USERNAME"]
node_password = ENV["NODE_PASSWORD"]
ARGV.each do |env|
puts "Launching environment #{env}"
end
I am working with OptionParser for the first time.
What I would like to know, is how I can make OptionParser handle arguments that are not prefixed with a certain flagname. I want to be able to write a statement like:
myscript.rb -d someoption -b someotheroption filename
where filename is the name of the file I want to work on. It is not prefixed by any option flag. How can I parse commands like the one above with OptionParser, and get a reference to filename?
OptionParser specifically handles options - that is, things starting with dashes. After it parses, the remaining arguments are left in ARGV. You can check for your filename there and exit with an error if it's missing.
With a slight modification on their minimal example,
require 'optparse'
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: example.rb [options]"
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
options[:verbose] = v
end
end.parse!
p options
p ARGV
p "Where is my hat?!" if ARGV.length == 0
You get this:
$ ruby parse.rb
{}
[]
"Where is my hat?!"
$ ruby parse.rb hat
{}
["hat"]
$ ruby parse.rb -v hat
{:verbose=>true}
["hat"]
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]
In my executable Ruby file I have the following:
#!/usr/bin/env ruby
require 'thor'
include Thor::Actions
class UI < Thor
# def self.source_root
# File.dirname(__FILE__)
# end
desc "makecal", "Generates postscript calendar to your desktop"
def makecal
# puts `ls ~`
puts run('ls ~')
# puts run "pcalmakecal -B -b all -d Helvetica/8 -t Helvetica/16 -S #{Time.now.month} #{Time.now.year} > ~/Desktop/#{Time.now.month}-#{Time.now.year}"
end
end
UI.start
In the terminal when I run the file as is I get an empty line as Thor's run command is returning a NilClass.
However, when I un-comment the puts `ls ~` and comment out Thor's run method I get an output of my home directory as expected.
I'm having trouble figuring out why I can't get Thor's run method to work like Ruby's ticks.
Any ideas where I may have went wrong?
Thanks for looking
I didn't put the include statement inside my class and that messed things up. The code should be:
#!/usr/bin/env ruby
require 'makecal'
class UI < Thor
include Thor::Actions
# def self.source_root
# File.dirname(__FILE__)
# end
#
desc "makecal", "Generates postscript calendar to your desktop"
def makecal
# puts `ls ~`
puts run('ls ~')
# puts run "pcal -B -b all -d Helvetica/8 -t Helvetica/16 -S #{Time.now.month} #{Time.now.year} > ~/Desktop/#{Time.now.month}-#{Time.now.year}"
end
end
UI.start
Thor's documentation on this method is actually wrong and incomplete. It documents that it returns the "contents of the command" (which I assume means the standard output), but it, by defualt, does nothing.
But, you can, apparently, use the :capture option to get what you want:
unless options[:pretend]
config[:capture] ? `#{command}` : system("#{command}")
end
So, try doing
puts run("ls ~", :capture => true)
And see if that does it.
I have created one ruby script that I want to run with some flags on console say -v flag prints output on console and -o stores output in new file with file name I am taking from console using gets()
My code has following structure:
puts "Enter filename to analyze:\n\n"
filename = gets().chomp
puts "Provide filename to store result in new text file:\n\n"
output = gets().chomp
filesize = File.size(filename)
puts "File size in Bytes:\n#{filesize.to_i}\n"
pagecontent = filesize - 20
puts "\n\nData:\n#{pagecontent}\n\n"
File.open(filename,'r') do |file|
#whole process with few do..end in between that I want to do in 2 different #ways.
#If I provide -v flag on console result of this code should be displayed on console
#and with -o flag it should be stored in file with filename provided on console #stored in output variable declared above
end
end
Use stdlib OptionParser