解析Rbox执行命令返回的文件统计信息

时间:2015-01-06 21:52:33

标签: ruby regex

我是Ruby编程的新手,现在我正在使用Rbox / Rye编写一些测试自动化ruby脚本。
作为测试的一部分,客户将一个+ 10GB的文件上传到ftp主机 该脚本每分钟检查文件是否仍在上传,上传完成或上传失败 对于测试,我使用Rbox / Rye execute shell命令查找文件统计信息:

def check_file_upload()
    rbox = Rye::Box.new("#{@host}")
    rbox.disable_safe_mode
    result = rbox.execute "stat #{@file}"
end

stats = file.check_file_upload()
puts stats

" put"正确打印文件统计信息。格式与我执行" stat文件相同的格式" linux主机上的命令。 现在,有没有办法可以实际解析由
返回的值     check_file_upload()
方法。我可以使用Ruby内置的正则表达式,或者grep / awk,从返回的文件统计信息中选择特定信息。
以下是文件统计信息:

File: `/home/user/file_name.dmp'  
Size: 11594768384   Blocks: 22668184   IO Block: 4096   regular file  
Device: 802h/2050d  Inode: 57442314    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1504/user)   Gid: ( 1504/user)  
Access: 2015-01-06 11:32:17.000000000 -0700  
Modify: 2015-01-06 11:38:59.000000000 -0700  
Change: 2015-01-06 11:38:59.000000000 -0700 

更具体地说,我想挑选文件大小,访问,修改和更改值

2 个答案:

答案 0 :(得分:0)

是的,这对正则表达式来说是一个简单的任务。这是一个解析来自" stat"的有趣位的类。 string并将它们公开为属性:

class FileStatInfo
  attr_reader :size, :access, :modify, :change
  def initialize(string)
    string.split(/\n/).each do |line|
      if line =~ /^Size:\s*(\d+)/
        @size = $1.to_i
      elsif line =~ /^Access:\s*(.*)/
        @access = $1.strip # Or Date.parse($1.strip)
      # ...
      end
    end
  end
end

# ...

stat_info = FileStatInfo.new(file.check_file_upload)
stat_info.size # => 11594768384
stat_info.access # => "2015-01-06 11:32:17.000000000 -0700"

答案 1 :(得分:0)

使用str提取字符串check_file_upload()后,可以构建一个哈希来保存感兴趣的值。

<强>代码

def extract(str, keepers)
  r = /\w+:\s(?:\S+\s)*\S+/
  str.lines.each_with_object({}) do |line, h|
    line.scan(r).each do |s|
      k,_,v = s.partition(/:\s+/)
      v = v.to_i if v =~ /^\d+$/
      h.update({ k=>[v] }) { |_,ov,nv| ov+nv } if keepers.include?(k)
    end
  end
end

示例

我理解以下是check_file_upload()生成的典型字符串:

str =
"Size: 11594768384   Blocks: 22668184   IO Block: 4096   regular file  
Device: 802h/2050d  Inode: 57442314    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1504/user)   Gid: ( 1504/user)  
Access: 2015-01-06 11:32:17.000000000 -0700  
Modify: 2015-01-06 11:38:59.000000000 -0700  
Change: 2015-01-06 11:38:59.000000000 -0700"

数组keepers标识要从此字符串中提取的数据:

keepers = %w{ Size Access Modify Change }
  #=> ["Size", "Access", "Modify", "Change"]

extract(str, keepers)
  #=> {"Size"=>[11594768384],
  #    "Access"=>["(0644/-rw-r--r--)", "2015-01-06 11:32:17.000000000 -0700"],
  #    "Modify"=>["2015-01-06 11:38:59.000000000 -0700"],
  #    "Change"=>["2015-01-06 11:38:59.000000000 -0700"]} 

<强>解释

我们的正则表达式是:

r = /\w+:\s(?:\S+\s)*\S+/

对于上面的示例:

str.lines
  #=> ["Size: 11594768384   Blocks: 22668184   IO Block: 4096  regular file \n",
  #    "Device: 802h/2050d  Inode: 57442314    Links: 1\n",
  #    "Access: (0644/-rw-r--r--)  Uid: ( 1504/user)   Gid: ( 1504/user)  \n",
  #    "Access: 2015-01-06 11:32:17.000000000 -0700  \n",
  #    "Modify: 2015-01-06 11:38:59.000000000 -0700  \n",
  #    "Change: 2015-01-06 11:38:59.000000000 -0700"]

Enumerable#each_with_object创建一个由块变量h表示的初始空哈希,并将数组str.lines的每个元素传递到块中,并将其分配给块变量{{1 }}。最初,

line

在我们计算的块中:

line = "Size: 11594768384   Blocks: 22668184   IO Block: 4096  regular file \n"
h = {}

请注意,a = line.scan(r) #=> ["Size: 11594768384", "Blocks: 22668184", "Block: 4096"] 被错误地提取,但不管那个字段是不是必需的。

"IO Block: 4096   regular file"

这里,第一个字符串a.each do |s| k,_,v = s.partition(/:\s+/) v = v.to_i if v =~ /^\d+$/ h.update({ k=>[v] }) { |_,ov,nv| ov+nv } if keepers.include?(k) end h #=> {"Size"=>[11594768384]} 传入其块

each

所以

s = "Size: 11594768384"

我们使用Hash#update(a.k.a。k,_,v = s.partition(/:\s+/) #=> ["Size", ": ", "11594768384"] v =~ /^\d+$/ #=> 0 v = v.to_i if v =~ /^\d+$/ #=> 11594768384 h.update({ k=>[v] }) { |_,ov,nv| ov+nv } if keepers.include?(k) #=> {}.update({ "Size"=>[11594768384] }) if # ["Size", "Access", "Modify", "Change"].include?("Size") #=> true h #=> { "Size=>[11594768384] } )的形式,它使用块来解析合并的两个哈希中包含的键的值。

由于merge!既不包含keepers也不包含"Blocks",因此这些键的哈希值不会合并到"Block"中。

对于h的下一个元素:

str.lines

line = "Device: 802h/2050d Inode: 57442314 Links: 1\n" 中不包含任何键,因此哈希keepers中没有添加任何内容。以下一行:

h

line = "Access: (0644/-rw-r--r--) Uid: ( 1504/user) Gid: ( 1504/user) \n" 添加到哈希值,因此我们得到:

{ "Access"=>["(0644/-rw-r--r--)"] }

接下来,

h = { "Size"=>[11594768384], "Access"=>["(0644/-rw-r--r--)"] }

所以

line = "Access: 2015-01-06 11:32:17.000000000 -0700  \n"

从这个数组传入其块的唯一元素是{<1}}:

a = line.scan(r)
  #=> ["Access: 2015-01-06 11:32:17.000000000 -0700"] 

由于each已包含密钥s = "Access: 2015-01-06 11:32:17.000000000 -0700" k,_,v = s.partition(/:\s+/) #=> ["Access", ": ", "2015-01-06 11:32:17.000000000 -0700"] v =~ /^\d+$/ #=> nil v = v.to_i if v =~ /^\d+$/ # no conversion to integer h.update({ k=>[v] }) { |_,ov,nv| ov+nv } if keepers.include?(k) #=> {"Size"=>[11594768384], # "Access"=>["(0644/-rw-r--r--)", "2015-01-06 11:32:17.000000000 -0700"]} ,因此调用h的块以确定执行合并后k => Access"的值。三个块变量是:

update

"Access"的值是数组k = "Access" # not used, so replaced with an underscore ov = ["(0644/-rw-r--r--)" # "old" value nv = ["2015-01-06 11:32:17.000000000 -0700"] # "new" value "Access"的总和,如上所示。

ov的其余元素的处理方式类似。