【问题标题】:How to use sed to insert after pattern conditionally如何使用 sed 在模式后有条件地插入
【发布时间】:2019-02-06 19:41:26
【问题描述】:

请帮助我了解更高级的 sed 语法。按照我的理解,我可以在一个字符串中使用两个 sed 命令来搜索模式,然后有条件地插入该模式之后。这是目标。我有一个这样的文件:

[PATTERN]
String

只有当“String”不存在时,我才需要 sed 在 [PATTERN] 之后插入“String”。

"String" 使用 Ansible 变量,基本上是这样的:

{{ hostname.droplet.name }} ansible_ssh_host={{ hostname.droplet.ip_address }}

这翻译成

hostname ansible_ssh_host=X.X.X.X

所以最终我将有以下现实世界(非概念性)示例:

[DROPLETS]
ilovetacos ansible_ssh_host=127.0.0.1

如果 [DROPLETS] 下面没有匹配的行,则追加该行。如果特定的主机名行已经存在,则不要再次添加该行。

我可以处理第一部分:

sed '/\[DROPLETS\]/a STRING' inventory

现在这是我的第一个问题。我不知道如何处理 sed 命令中的 ansible 变量?也许是这样?

sed '/\[DROPLETS\]/a "{{ hostname.droplet.name }} ansible_ssh_host={{ hostname.droplet.ip_address }}"' inventory

下一部分是添加条件检查。我曾考虑过先 greping 这条线,然后再通过管道传输到 sed,但似乎有更好的方法可以使用单个 sed 命令完成所有这些操作。有人可以帮助我使用这种更高级的语法吗?

谢谢

【问题讨论】:

  • 为什么不用 Ansible 的 lineinfile 模块调用替换 sed
  • 是的,我完全同意,但具有讽刺意味的是,我尝试这种方式的全部原因是我们在 lineinfile 模块中发现了一个错误。那是另一种蠕虫,但基本上,尽管验证了变量的内容,lineinfile 模块仍无法将所有输出写入文件。我们测试了一切。想也许文件被锁定了。认为变量可能不完整,等等。我们最终不得不放弃模块并选择纯 shell 选项。我根本不喜欢这样做......感觉不对,并且反对 Ansible 的一切,但到目前为止我们别无选择。
  • 正确的建议!
  • 因此,根据您的示例,您似乎正在动态构建库存文件。这表明[DROPLETS] 下可能有任意数量的主机,所以您不一定只是在下面直接寻找匹配项?可靠地解决这将是相当棘手的。在深入探讨之前,您是否考虑过编写动态库存脚本? (docs.ansible.com/ansible/latest/dev_guide/…)
  • 完全同意@clockworknet 但如果由于某种原因这不是你的情况,那么我的后续建议是使用实际的脚本语言,因为 sed 真的不是为了做很多“有状态的” “ 事物。你也可以使用awk,它有更丰富的变量,如果你真的坚决反对使用脚本语言...

标签: bash sed ansible


【解决方案1】:

我仍然坚持我的评论,这取决于您的用例,使用dynamic inventory scripts 可能是要走的路。但是,如果您要添加的行在文件中最多只能存在一次,这可能满足您的要求:

(归功于 Konstantin Suvorov,因为这包括采用 from his website 的技术)

- name: Build inventory string
  set_fact:
    inventory_string: "{{ hostname.droplet.name }} ansible_ssh_host={{ hostname.droplet.ip_address }}"
    inventory_file: /tmp/sssd.conf
- name: Add inventory string to inventory file if necessary
  shell: |
    grep "^{{ inventory_string }}" {{ inventory_file }} ||
    sed -i '/\[DROPLETS\]/a {{ inventory_string }}' {{ inventory_file }}
  register: output
  changed_when: output.stdout != inventory_string

shell 任务中发生的一些事情:

  • shell 命令定义了两个命令,由|| 分隔。这是一个 Unix shell 结构,它表示后面的命令只有在它前面的命令失败时才会运行。然后我们使用grep 来查看字符串是否已经存在。如果grep 找不到它,则运行sed 添加它的命令
  • 如果不指定changed_when 条件,任务将始终报告“已更改”。我们register 任务的输出。如果grep 找到您的字符串,stdout 将仅包含您的字符串,因此我们可以检查它的存在以确定是否触发了sed 命令。

【讨论】:

  • 这行得通。我只是遇到了很多其他问题,但最终这解决了我的具体问题。谢谢!
猜你喜欢
  • 2013-08-22
  • 2013-11-24
  • 1970-01-01
  • 1970-01-01
  • 2018-04-15
  • 1970-01-01
  • 2021-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多