Ansible "lineinfile": add new line (with PATH=) or append to existing line (with PATH=)

10,111

Solution 1

You are using the backrefs: true flag, which prevents lineinfile from changing the file if the line does not already exist. From the docs:

Used with state=present. If set, line can contain backreferences (both positional and named) that will get populated if the regexp matches. This flag changes the operation of the module slightly; insertbefore and insertafter will be ignored, and if the regexp doesn't match anywhere in the file, the file will be left unchanged. If the regexp does match, the last matching line will be replaced by the expanded line parameter.

Since you need to create the line if it does not exist, you should use:

- name: Check whether /etc/environment contains PATH
  command: grep -Fxq "PATH=" /etc/environment
  register: checkpath
  ignore_errors: True
  changed_when: False

//updatePath.yml
- name: Add path to /etc/environment
  lineinfile:
    dest=/etc/environment
    state=present
    regexp='^PATH='
    line='PATH={{ my_extra_path }}'
  when: not checkpath.rc == 0

- name: update /etc/environment
  lineinfile:
    dest=/etc/environment
    state=present
    backrefs=yes
    regexp='PATH=({{ my_path }}:?)?({{ my_extra_path }}:?)?(.*)'
    line='PATH={{ my_extra_path }}:{{ my_extra_path }}:\3'
  when: checkpath.rc == 0

Solution 2

Same idea as here : https://stackoverflow.com/a/40890850/7231194 or here : https://stackoverflow.com/a/40891927/7231194

Steps are:

  • Try to replace the line.
  • If replace mod change it. Cool, it's over !
  • If replace mod doesn't change, add the line

Example

# Vars
- name: Set parameters
  set_fact:
    my_path: "/usr/bin:/usr/sbin"
    my_extra_path: "/usr/extra/path"

# Tasks
- name: Try to replace the line if it exists
  replace:
    dest    : /dir/file
    replace : 'PATH={{ my_extra_path }}'
    regexp  : '^PATH=.*'
    backup  : yes
  register  : tryToReplace

# If the line not is here, I add it
- name: Add line
  lineinfile:
    state   : present
    dest    : /dir/file
    line    : '{{ my_extra_path }}'
    regexp  : ''
    insertafter: EOF
  when: tryToReplace.changed == false
Share:
10,111
Dominik
Author by

Dominik

Founder of azine.me: the one and only peer-to-peer IT contractor referral platform. Entrepreneur, Software Engineer, Programmer and Architect, mainly using Java, PHP & JavaScript

Updated on July 31, 2022

Comments

  • Dominik
    Dominik almost 2 years

    I am trying to replace or append a path part to the path definition in /etc/environment on a linux box.

    Here's what I have:

    //all.yml
    my_path: "/usr/bin:/usr/sbin"
    my_extra_path: "/usr/extra/path"
    

    In my role-file:

    //updatePath.yml
    - name: update /etc/environment
      lineinfile:
        dest=/etc/environment
        state=present
        backrefs=yes
        regexp='PATH=({{ my_path }}:?)?({{ my_extra_path }}:?)?(.*)'
        line='PATH={{ my_extra_path }}:{{ my_extra_path }}:\3'
    

    Now when I run the role, it works fine updating an existing PATH-line, but not creating duplicates within the line or even duplicate lines. So far so good.

    When there is no line with "PATH=" present, I would expect it to add a new one. But it doesn't.

    Is my expectation wrong or where lies the problem?

  • Dominik
    Dominik over 7 years
    No, removing the backrefs: true does not work. It creates duplicates if you re-run the ansible role and also it does not add to an existing path, but replace it. To be able to add to the path I need the backrefs: true. See the \3 at the end of line=
  • MillerGeek
    MillerGeek over 7 years
    Updated my answer to conditionally create the line if it does not exist, but otherwise update the line with backrefs. Backrefs is currently incompatible with creating a line which does not exist, so you need multiple tasks.