通过ARGV / ARGF接受多个命令行参数

时间:2014-08-20 16:44:02

标签: ruby

我试图让我的代码能够从命令行输入接受多个日志文件,以便根据不同的分隔符进行解析,并接受命令来解析某个日志文件的所有步骤。

它目前一次只能接受一个命令,并且它解析的日志文件是在代码中确定的,而不是变量@log_file下的命令行输入:

@log_file = "07-07-14 to 07-13-14_debug.log"
@log_levels = ['DEBUG', 'INFO ', 'WARN ', 'ERROR', 'FATAL']

def error_sort
  @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(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

command_line = ARGV[0..1]

ARGV.each do |num|
  if command_line == ["--step", "#{num}"]
    read_log("#{num}".to_i)
  elsif command_line == ["--sort"]
    error_sort
  else
    nil
  end
end

思想?

2 个答案:

答案 0 :(得分:2)

使用命令行参数解析像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

有关OptionParser的更多信息:

修改

为了允许两次使用相同的标志,例如--step 3 --step 5,我们可以将:step地图中的options条目更改为指定数字的数组,如下所示:

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

然后使用:step参数更改程序的语义,现在这是一个数组而不是一个数字:

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

所有非选项参数都保留在ARGV中,因此您可以轻松启用多个文件处理:

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

答案 1 :(得分:2)

您的代码需要一些重构。除了使用OptionParser之外,使用File.open附加到文件效率很低。冥想:

LOG_FILE = "07-07-14 to 07-13-14_debug.log"
LOG_LEVELS = ['DEBUG', 'INFO ', 'WARN ', 'ERROR', 'FATAL']

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

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

在附加时反复打开和关闭文件会通过强制搜索到文件结尾,缓冲区在它们已满之前刷新等来减慢I / O子系统。相反,请根据需要打开文件,写入它在处理相同类型的数据时,然后关闭它以让系统重用文件句柄。