用木偶法特勒返回多个自定义事实

时间:2013-10-01 23:13:20

标签: ruby puppet facter

我正在尝试将系统上的用户添加为傀儡事实。我不是一个ruby程序员,下面的代码正确地生成了用户,但是他们的uid是完全相同的(密码文件中最后一个条目的uid)。如果uid超出范围,我会期望一个未知的符号错误,如果Facter.add最后只被调用一次,我希望只有一个用户,最后一个用户,与uid相同。我不明白如果没有另一个人这样做就可以迭代......

File.open("/etc/passwd", "r") do |passwords|
  while pw_entry = passwords.gets
    user, pw, uid, gid, gecos, home, shell = pw_entry.split(/:/)

    Facter.add("user_" + user) do
      setcode do
        uid
      end
    end
  end
end

在探索中,我发现其他人几乎有同样的问题,这就是解决方案(这对我也有效):

require 'etc'

Etc.passwd { |user|

    Facter.add("user_" + user.name) {
      setcode {
        user.uid
      }
    }
}

......但我不明白其中有什么不同。它就像对Facter.add块的调用一样,在循环结束时被缓冲并一次运行,并且Etc加载了所有passwd,因此user.uid索引到数组中,时间无关紧要。对于程序语言而言,这将是一件奇怪的事情......

1 个答案:

答案 0 :(得分:2)

你说的如下:

File.open("/etc/passwd", "r") do |passwords|
  while pw_entry = passwords.gets
      user, pw, uid, gid, gecos, home, shell = pw_entry.split(/:/)
      print uid
  end
end

几乎相当于:

require 'etc'
Etc.passwd { |user|
  print uid
}

事实上,这两个红宝石片段会产生完全相同的结果。

唯一的区别是最后一个方法使用另一种方法迭代passwd文件。它使用一个闭包,它接收参数user作为输入。此user是匿名函数范围内唯一存在的user

现在,关于你的两个方法之间差异的问题:

当你引用不属于闭包本身的ruby闭包内的变量(即外部变量)时,对该(外部)作用域内该变量的符号的引用存储在闭包的代码中。由于在第一种方法中,您在同一范围内重用相同的符号,因此在添加所有事实后调用闭包的代码时,uid引用最后已知的uid值。这称为outer variable trap

解决此问题的一种方法是让每个uid存在于自己的范围内。

def addUserFact(passwd_entry)
  user, pw, uid, gid, gecos, home, shell = passwd_entry.split(/:/)   
  Facter.add("user_" + user) do
    setcode do
      uid
    end
   end
end

File.open("C:/cygwin/etc/passwd", "r") do |passwords|
  while pw_entry = passwords.gets
    addUserFact(pw_entry)
  end
end