Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backslashes in regex_replace #33202

Closed
kustodian opened this issue Nov 22, 2017 · 1 comment
Closed

Backslashes in regex_replace #33202

kustodian opened this issue Nov 22, 2017 · 1 comment

Comments

@kustodian
Copy link
Contributor

@kustodian kustodian commented Nov 22, 2017

ISSUE TYPE
  • Bug?
COMPONENT NAME

Core

ANSIBLE VERSION
ansible 2.5.0 (devel 1ee511f82c) last updated 2017/11/22 20:37:38 (GMT +200)
SUMMARY

While I was upgrading from Ansible 2.3 to 2.4 I came across some changes in how backslashes are used to escape characters in regex_replace filter, so I made a little test playbook to show all the correct ways you can use backslashes. I told @abadger that I will make an issue for this, so here it is.

STEPS TO REPRODUCE

Here is a test playbook:

# fun_with_backslashes.yml
---
- hosts: localhost
  connection: local
  gather_facts: no
  vars:
    full_name: 'John Smith'
  tasks:
    - name: Backslashes msg in single quotes
      debug:
        msg: '{{ full_name | regex_replace("^([\S]+).*", "\1") }}'

    - name: Backslashes msg in double quotes
      debug:
        msg: "{{ full_name | regex_replace('^([\\S]+).*', '\\1') }}"

    - name: Backslashes with var using single quotes
      debug:
        var: full_name | regex_replace('^([\S]+).*', '\1')

    - name: Backslashes with var using double quotes
      debug:
        var: full_name | regex_replace("^([\S]+).*", "\1")

    - name: Backslashes in a template
      template:
        src: backslashes.j2
        dest: /tmp/backslashes
      check_mode: yes

    - name: Lookup template
      debug:
        msg: '{{ lookup("template", "backslashes.j2") }}'

and the template:

{# backslashes.j2 #}
{{ full_name | regex_replace("^([\\S]+).*", "\\1") }}
{{ full_name | regex_replace("^([\S]+).*", "\\1") }}
{% if full_name | regex_replace("^([\\S]+).*", "\\1") == 'John' %}
John
{% endif %}
{% if full_name | regex_replace("^([\S]+).*", "\\1") == 'John' %}
John
{% endif %}

These are all the combination I could think of that work correctly. The output of running this playbook (with -D to be able to see results of the template module):

$ ansible-playbook fun_with_backslashes.yml -D

PLAY [localhost] **********************************************************************************************************************************************************************************************

TASK [Backslashes msg in single quotes] ***********************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "John"
}

TASK [Backslashes msg in double quotes] ***********************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "John"
}

TASK [Backslashes with var using single quotes] ***************************************************************************************************************************************************************
ok: [localhost] => {
    "full_name | regex_replace('^([\\S]+).*', '\\1')": "John"
}

TASK [Backslashes with var using double quotes] ***************************************************************************************************************************************************************
ok: [localhost] => {
    "full_name | regex_replace(\"^([\\S]+).*\", \"\\1\")": "John"
}

TASK [Backslashes in a template] ******************************************************************************************************************************************************************************
--- before
+++ after: /tmp/tmpy3Q4hm/backslashes.j2
@@ -0,0 +1,4 @@
+John
+John
+John
+John

changed: [localhost]

TASK [Lookup template] ****************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "John\nJohn\nJohn\nJohn\n"
}
EXPECTED RESULTS

Results mostly look as expected:

  • Single backslash:
    • in YAML between single quotes
    • in YAML without quotes (doesn't matter if you use single or double quotes inside regex_replace)
  • Double backslash:
    • in YAML between double quotes
    • in templates
ACTUAL RESULTS

Only strange thing is that inside templates you can use both double and single quotes inside a regex, but you have to use double quotes for back reference, which means both of these lines work in templates

{{ full_name | regex_replace("^([\\S]+).*", "\\1") }}
{{ full_name | regex_replace("^([\S]+).*", "\\1") }}

In my opinion the second line feels like a bug and it should be consistent.

@sivel

This comment has been minimized.

Copy link
Member

@sivel sivel commented May 10, 2019

@sivel sivel closed this May 10, 2019
@ansible ansible locked and limited conversation to collaborators Aug 5, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
4 participants
You can’t perform that action at this time.