I was trying to replace one string in a file. For example:
$PASSWORD="oldpassword"
with:
$PASSWORD="newpassword"
Here is the Ansible task which should do this:
- name: change password with lineinfile
lineinfile:
dest: test.txt
regexp: '^$PASSWORD='
line: '^$PASSWORD="newpassword"'
state: present
backrefs: yes
Unfortunately I can't find the reason why it isn't working. I cannot replace it with the new string.
I was also trying without backrefs and the string was added instead of replaced.
Please advise.
Thank you.
From Regular expression operations:
$: Matches the end of the string or just before the newline at the end of
the string
So, escape $ with backslash.
- lineinfile:
dest: /tmp/test.txt
regexp: '^\$PASSWORD='
line: '$PASSWORD="newpassword"'
state: present
Also you don't need to use the backrefs parameter with your example, because your regular expression doesn't have backreferences.
Related
I am trying to write a playbook to add log forwarder lines to syslog.conf on AIX.
The tasks looks like this:
- set_fact:
log_servers:
- "auth.info\t#10.10.10.100"
- "*.info\t#log.example.com"
- lineinfile:
path: /etc/syslog.conf
regexp: '^{{item}}'
line: '{{item}}'
loop: "{{log_servers}}"
The first line is inserted with no issues, but I get a Python exception when the second line is encountered because of the leading asterisk.
An asterisk can be anywhere else in the line, but not at the start of the line. And escaping with a backslash (\*.info\t#log.example.com) causes a JSON parsing error, and a double backslash (\\*.info\t#log.example.com) just inserts a backslash at the front of the line.
Any advice on how to get around this?
Your issue is coming from the fact that you are trying to use the same string for a regex (where you need to escape the star) and for the line to add (where you don't need to escape the star).
There is a way to resolve this, though, it is to use the builtin regex_escape filter.
And so, your two task should become:
- set_fact:
log_servers:
- "auth.info\t#10.10.10.100"
- "*.info\t#log.example.com"
- lineinfile:
path: /etc/syslog.conf
regexp: '^{{ item | regex_escape() }}'
line: '{{ item }}'
loop: "{{ log_servers }}"
I want to remove only 'fsck.mode=auto' from the following line using ansible.
foo bar foo.bar=hold fsck.mode=auto foo foo bar foo
The hosts, root user and other privileges are set up else where in the project.
I prefer to use lineinfile if possible over replace. I don't want to delete the whole line but rather only remove whats in the regexp with ''.
- name: remove fsck
lineinfile:
dest: /etc/grub2.cfg
regexp: 'fsck.mode=auto'
line: ''
- name: Replacing the square brackets and single quotes on new VM IP address in hosts
hosts: 127.0.0.1
connection: local
become: true
tasks:
- name: Replacing the brackets from the end of the new ip with whitespace
replace:
path: /etc/ansible/hosts
regexp: \'\]
replace: ''
The above works for me to replace "']" with ''
edit: Just noticed you don't want to use 'replace' my bad. I believe you can use 'state=present' to replace using lineinfile
https://docs.ansible.com/ansible/2.4/lineinfile_module.html Take note of the 'backrefs' option
I think you are interested in backrefs. The code below does what you need. You can also play with white spaces if you want
- name: Change match only
lineinfile:
path: /whatever/file.txt
regexp: '^(. *)fsck.mode=auto (. *)$'
line: '\1\2'
backrefs: yes
Without those spaces between . and * (formatting piece of s>>t)
I am trying to replace a pattern with a string containing a backslash
- name: Replace test
replace: dest=/tmp/test
regexp="test"
replace="test, \"
I get the following error in ansible:
The error appears to have been in '/home/deployer/ansible/roles/test/tasks/configuration.yml': line 11, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Replace test
^ here
Despite the fact, that you've omitted the actual error message starting with word ERROR!, here is the fix for your problem:
- name: Replace test
replace:
dest: /tmp/test
regexp: test
replace: 'test, \\'
mind the indentation
use dict-style syntax for complex string manipulation (not param=value shorthand)
escape slash in regexp-replace expression
Another easy solution is to leave escaping backslash to ansible itself. This is how i would have done.
- set_fact:
replacer: '\'
- name: Replace test
replace:
dest: /tmp/test
regexp: test
replace: 'test, replacer'
I'm new to Ansible and trying to modify a line in /etc/default/grub to enable auditing.
I need to add audit=1 within the quotes somewhere on a line that looks like:
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap biosdevname=0 net.ifnames=0 rhgb quiet net.ifnames=0"
So far I've managed to delete the line and am only left with
net.ifnames=0, audit=1
when I use something like
lineinfile:
state: present
dest: /etc/default/grub
backrefs: yes
regexp: "net.ifnames=0"
line: "\1 audit=1"
Can this be done?
You may try this:
- lineinfile:
state: present
dest: /etc/default/grub
backrefs: yes
regexp: '^(GRUB_CMDLINE_LINUX=(?!.* audit)\"[^\"]+)(\".*)'
line: '\1 audit=1\2'
This will add audit=1 (with a leading space) just before closing double quote. It will not match without double quotes.
And it tries to be idempotent: doesn't match lines that already have audit (with a leading space) after GRUB_CMDLINE_LINUX=.
I'd recommend to use sites like regex101 to test your regular expressions first (there's also a substitution mode there).
When you're satisfied with the result, proceed with the Ansible task.
I wanted to make sure the parameter is also set to the correct value, so I used this replace invocation:
replace:
path: /etc/default/grub
regexp: '^(GRUB_CMDLINE_LINUX=(?:(?![" ]{{ option | regex_escape }}=).)*"?)\s*(?:{{ option | regex_escape }}=\S+\s*)?(.*")$'
replace: '\1 {{ option }}={{ value }}\2'
vars:
option: audit
value: 1
This works if the option wasn't present previously, if it was but had the wrong option (only changes the value then) and if the whole string was empty (but adds a space before the option then). Also, it uses regex_escape to correctly work with option names that contain dots and the likes, and you only have to specify them once.
When I use lineinfile in ansible it is not writing ', " characters
lineinfile: 'dest=/home/xyz state=present line="CACHES="default""'
it is giving CACHES=default
but the desired output is CACHES="default"
How to achieve this?
it appears you can escape the quotes:
- lineinfile: dest=/tmp/xyz state=present line="CACHES=\"default\""
That gives this output:
$ cat /tmp/xyz
CACHES="default"
You don't need to escape single quotes that are inside double quotes:
- lineinfile: dest=/tmp/xyz state=present line="CACHES=\"default\" foo='x'"
cat /tmp/xyz
CACHES="default" foo='x'
source: YAML specification, stackoverflow answer
Ansible 1.9.2 contains a bug (https://github.com/ansible/ansible/issues/10864), which fails to insert escaped double quotes at the beginning or end of the line.
E.g., the following
- name: /home/core/linetest
lineinfile: dest="/home/core/linetest" line="\"ma\"ok\"in\""
will result in missing first and last double-quotes (even though you escaped it).
#/home/core/linetest
ma"ok"in
To compensate for this bug, you could add a PREFIX to the starting and ending double quotes, and subsequently removing it.
- name: PREFIX first and last escaped double quotes with 'KUCF'
lineinfile: dest="/home/core/linetest" line="KUCF\"main\"KUCF"
- name: remove 'KUCF' PREFIX
replace: dest="/home/core/linetest" regexp="KUCF" replace=""
which should give you
#/home/core/linetest
"main"
Make sure that your chosen PREFIX will never be used in the context of the destination file. In general, the longer and more random the PREFIX, the less likely it will clash with existing content in your destination file.
Alternatively, you could upgrade your Ansible to the latest branch.
If the content to be substituted is in a variable higher up in the playbook, it seems that you need to escape the escape characters instead of the quotes, something like this
---
- hosts: tomcat
vars:
classpath: "CLASSPATH=\\\"$CATALINA_HOME/bin/foo.jar\\\""
tasks:
- lineinfile: dest="/tomcat/bin/setenv.sh" line="{{ classpath }}" state=present
ends up with a line like this in the resulting file
CLASSPATH="$CATALINA_HOME/bin/foo.jar"
Just a follow up to this, above examples did not work for me when trying to create a batch file on a windows box using win_lineinfile. The file was being created, the line was being inserted, but the quotes and backslashes were formatted terribly. This was with ansible 2.4. What I finally ended up doing per a co workers suggestion was some inline jinja templating;
- name: insert our batch file contents
win_copy:
dest: C:\QAAutomation\files\posauto.bat
force: yes
content: |
{% raw %}"C:\Program Files (x86)\NUnit 2.6.3\bin\nunit-console.exe" "C:\QAAutomation\files\1POS Automation\Application Files\Bin\Automation.dll" > "c:\QAAutomation\results\nunit-console-output.txt" {% endraw %}