使用sed递归查找和替换

时间:2013-12-06 13:00:22

标签: ruby bash recursion sed chef

我正在使用厨师食谱来更新节点上的配置文件。该文件的内容如下所示:

server server1.domain.com
server server2.domain.com

我的属性文件中定义了一个ruby数组,如下所示:

default['servers'] = %w(xyz.domain.com abc.domain.com)

我想以递归方式使用sed替换文件中的服务器值,以便我的文件更新如下:

server xyz.domain.com
server abc.domain.com

我在我的食谱中尝试了以下ruby循环:

(node['servers']).each_with_index do |ntserver,index|
bash "server set"  do

    code <<-EOH
    sed -i 's|server .*|server #{node['servers'].at(index)}|' /etc/ntp.conf
    EOH

    end
end

但是在运行chef-client并分别应用更改之后,配置文件的内容如下:

server abc.domain.com
server abc.domain.com

我是sed命令的新手,所以无法弄清楚我哪里出错了。 任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:3)

按照设计,您不应该使用Chef修改文件。相反,您使用cookbook_file资源覆盖整个文件,或者,如果您需要使用template资源将一些动态值插入到文件中。

答案 1 :(得分:1)

sed命令(你使用它的方式)非常简单;它仅执行(由于-i选项而在给定文件中就位)用字符串server .*替换匹配模式server #{node['servers'].at(index)}的每个字符串。它在整个文件中执行此操作,因此每个循环都会更改整个文件中的所有实例。

让我感到困扰的是你在原版中写了server1.domain.com,但是你得到的格式是server .*(意思是server,后跟一个空格{ {1}}以及任意数量的其他字符)。由于空间,这不应该匹配任何东西,所以根本不需要改变任何东西。但也许你只是在发布问题时错误地把那个空间放在那里。我假设你的实际代码中没有这样的空间,因为这样就可以适应观察到的现象。

因此,要一次只更改一行,您应该在循环中有一个计数器并且在搜索模式中具有迭代次数,因此第一次迭代时.*server1.*,{{ 1}}为第二个,依此类推。然后每次迭代只会改变一行,你应该得到你想要的结果。