Ansible lineinfile模块:不要添加新行

时间:2020-05-23 13:33:11

标签: ansible

我正在修改/boot/cmdline.txt以将容器功能添加到Raspberry Pi,所以我需要在同一行中将cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory添加到文件中。

我正在尝试使用lineinfile模块来完成此尝试,

- hosts: mypi
  become: yes
  tasks:
  - name: Enable container features
    lineinfile:
      path: /boot/cmdline.txt
      regex: " cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory"
      line: " cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory"
      insertafter: EOF
      state: present

我一直在尝试将insertafter修改为BOF,也使用insertbefore,使用正则表达式来匹配最后一个单词……但是最终却增加了回车符。我一直无法找到不添加新行的方法。

3 个答案:

答案 0 :(得分:2)

由于文件中只有一行,因此可以使用replacelineinfile来完成。这是replace版本:

  - name: Enable container features
    replace:
      path: cmdline.txt
      regexp: '^([\w](?!.*\b{{ item }}\b).*)$'
      replace: '\1 {{ item }}'
    with_items:
    - "cgroup_enable=cpuset"
    - "cgroup_memory=1"
    - "cgroup_enable=memory"

here

那里窃取了答案

答案 1 :(得分:2)

正如 Vladimir 指出的那样,不幸的是,Jack 的回答对于空文件是不够的,如果所需的参数已经存在于行的开头,那么它也会失败。 以下建议的解决方案应解决这些问题。特别是,它应该

  • 支持空文件,
  • 支持字符串中任意位置的现有参数,
  • 即使使用多行文件也要健壮(以防万一...),
  • 是幂等的,并且
  • 可以选择使用所需值更新现有密钥。
# cmdline.yml

- name: read cmdline.txt
  become: true
  slurp: "src={{ cmdline_txt_path }}"
  register: result_cmdline

- name: generate regular expression for existing arguments
  set_fact:
    regex_existing: '{{ "\b" + key|string + "=" + ("[\w]*" if update else value|string) + "\b" }}'
    key_value_pair: '{{ key|string + "=" + value|string }}'

- name: generate regular expression for new arguments
  set_fact:
    regex_add_missing: '{{ "^((?!(?:.|\n)*" + regex_existing + ")((?:.|\n)*))$" }}'

- name: update cmdline.txt
  become: true
  copy:
    content: '{{ result_cmdline.content
        | b64decode
        | regex_replace(regex_existing, key_value_pair)
        | regex_replace(regex_add_missing, key_value_pair + " \1")
      }}'
    dest: "{{ cmdline_txt_path }}"

用法:

- set_fact:
    cmdline_txt_path: /boot/cmdline.txt

- include_tasks: cmdline.yml
  vars:
    key: cgroup_enable
    value: memory
    update: false
    # will add the argument if the key-value-pair doesn't exist

- include_tasks: cmdline.yml
  vars:
    key: cgroup_enable
    value: cpu
    update: false

- include_tasks: cmdline.yml
  vars:
    key: cgroup_memory
    value: 1
    update: true
    # will replace the value of the first matching key, if found;
    # will add it if it's not found

但是,我可能遗漏了一些边缘情况 - 如果您发现任何问题,请告诉我。

答案 2 :(得分:1)

Q:“ Ansible lineinfile模块:不添加新行。找到不添加新行的方法。”

A:不可能。新行将始终由模块lineinfile添加。例如,请参见source

b_lines.insert(index[1], b_line + b_linesep)

这是添加新行的方式。此类添加将以b_linesep终止。查看变量如何为defined

b_linesep = to_bytes(os.linesep, errors='surrogate_or_strict')

当您要遍历文本文件的各行时使用os.linesep。内部扫描器可以识别os.linesep并将其替换为单个“ \ n”。

请参见What is os.linesep for?


模块replace的任务也无法解决此问题。它既不创建没有换行的行,也不以这种方式修改现有行。除此之外,它不是幂等的。

  - name: Enable container features
    replace:
      path: cmdline.txt
      regexp: '^([\w](?!.*\b{{ item }}\b).*)$'
      replace: '\1 {{ item }}'
    loop:
      - "cgroup_enable=cpuset"
      - "cgroup_memory=1"
      - "cgroup_enable=memory"

如果文件为空它将不执行任何操作

TASK [Enable container features]
ok: [localhost] => (item=cgroup_enable=cpuset)
ok: [localhost] => (item=cgroup_memory=1)
ok: [localhost] => (item=cgroup_enable=memory)

如果文件中存在该行,则此任务将对其进行更改

shell> cat cmdline.txt 
cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
ASK [Enable container features] *****************************************
ok: [localhost] => (item=cgroup_enable=cpuset)
--- before: cmdline.txt
+++ after: cmdline.txt
@@ -1 +1 @@
-cgroup_memory=1 cgroup_enable=memory cgroup_enable=cpuset
+cgroup_memory=1 cgroup_enable=memory cgroup_enable=cpuset cgroup_memory=1