How Can Same Program in Ruby Accept Input from User as Well as Command Line Arguments

How can same program in ruby accept input from user as well as command line arguments

gets will only read from the real $stdin (ie the user) if there are no command line arguments. Otherwise it'll take those arguments as files to concatenate as a virtual $stdin.

You can use STDIN.gets to make sure you're always using the right function.

You can also delete the arguments from ARGV as you go (or remove them all in one go), your gets should work correctly.

How can I get user input from command line with this program?

ARGV is an array. You have to get its first element.

print ARGV  # An array
x = ARGV[0]
print x

With ruby filename.rb 123, ARGV is ["123"] and x is "123".

When specifying command-line arguments Ruby no longer waits for input using gets

In addition to STDIN.gets like others have recommended, you can use plain gets if you call ARGV.clear beforehand. The regular gets works as expected if there aren't command like arguments to the script, but if there are, then it will read them. It's not really clear why you're using ./test.rb test.rb, but the second filename is a command line argument.

More specifically, if regular gets is called when ARGV is populated, then the result will be the contents of the file.

max@max ~> echo "content" > test.txt
max@max ~> ruby -e "puts ARGV.inspect; puts gets" test.txt
["test.txt"]
content

Accept multiple command-line arguments through ARGV/ARGF

This would be easily done using a command-line arguments parsing library like OptionParser.

require 'optparse'

LOG_LEVELS = ['DEBUG', 'INFO ', 'WARN ', 'ERROR', 'FATAL']

def error_sort(log_file)
LOG_LEVELS.each do |log_level|
File.readlines(log_file).each do |line|
if (line =~ /<#{log_level}>/ .. line =~ /<(?!#{log_level}).+>/) && line !~ /<(?!#{log_level}).+>/
File.open("#{log_level}.txt", "a") << line
end
end
end
end

def read_log(log_file, step)
File.readlines(log_file).each do |line|
if line.match /Recording dut_serial_number/
File.open("step_#{step}", "a") << line
elsif (line =~ /Beginning step ##{step} / .. line =~ /Beginning step #(?!#{step}).+ /) && line !~ /Beginning step #(?!#{step}).+ /
File.open("step_#{step}", "a") << line
else
nil
end
end
end

options = {}

optparse = OptionParser.new do |opts|
opts.on("--sort", "Explain what this option does here.") do
options[:sort] = true
end

opts.on("--step NUM", Integer, "Explain what this option does here.") do |num|
options[:step] = num # num is automatically converted to an Integer
end
end

optparse.parse! # all non-option arguments remain in ARGV

log_file = ARGV[0]

if options[:sort]; error_sort(log_file); end
if options[:step]; read_log(log_file, options[:step]); end

More information on OptionParser:

  • http://ruby.about.com/od/advancedruby/a/optionparser2.htm
  • http://ruby-doc.org/stdlib-2.1.2/libdoc/optparse/rdoc/OptionParser.html

EDIT:

In order to allow using the same flag twice, e.g. --step 3 --step 5, we can change the :step entry in our options map to be an array of specified numbers, like this:

options = {:step => []}

optparse = OptionParser.new do |opts|
...

opts.on("--step NUM", Integer, "Explain what this option does here.") do |num|
options[:step] << num
end
end

Then change the semantics of what your program does with the :step argument, which is now an array instead of a single number:

unless options[:step].empty?
options[:step].each {|n| read_log(log_file, n)}
end

All non-option arguments remain in ARGV, so you can enable multiple file processing easily:

ARGV.each do |log_file|
if options[:sort]
error_sort(log_file)
end

unless options[:step].empty?
options[:step].each {|n| read_log(log_file, n)}
end
end

How to pass text file as an argument in Ruby

On your shell, invoke the ruby script followed by the name of the .txt file, like this:

ruby foo.rb test_list.txt

The variable ARGV will contain references to all the arguments you've passed when invoking the ruby interpreter. In particular, ARGV[0] = "test_list.txt", so you can use this instead of hardcoding the name of the file:

File.open(ARGV[0]).each do |line|
puts line
end


On the other hand, if you want to pass the content of the file to your program, you can go with:

cat test_list.txt | ruby foo.rb

and in the program:

STDIN.each_line do |line|
puts line
end

How do I use the system() command to pass in user input?

You should look into the Open3 library from the Ruby stdlib. It gives you more control over "shelling out".

output, status = Open3.capture2("./script", :stdin_data => "I am STDIN")

Read input from console in Ruby?

Are you talking about gets?

puts "Enter A"
a = gets.chomp
puts "Enter B"
b = gets.chomp
c = a.to_i + b.to_i
puts c

Something like that?

Update

Kernel.gets tries to read the params found in ARGV and only asks to console if not ARGV found. To force to read from console even if ARGV is not empty use STDIN.gets

User input to create factorial

You actually seem to be asking for two different things. The first thing you want is an application that does something like this

$ ruby factorial.rb
> Please input a non-negative integer
(GET USER INPUT)
> The factorial of (USER INPUT) is (FACTORAIL OF USER INPUT)

And a command line tool that does something like this

$ fact 10
> 3628800

The first one could look something like this

def fact(n)
(1..n).inject(:*)
end
puts 'Please input a non-negative integer'
a = gets.to_i
puts "The factorial of #{a} is #{fact(a)}"

The second one could look something like this

#!/usr/bin/ruby
puts (1..ARGV[0].to_i).inject(:*)

Changing behavior of gets, when reading from command line, in Ruby

Check the docs:

If Kernel.gets sees that ARGV is set, it uses them as filenames to
feed instead of reading from stdin. So use an expicit: $stdin.gets



Related Topics



Leave a reply



Submit