How can I match `\s` or `\t` in a `search` test?

Here is an example:

  • hosts: localhost
    gather_facts: false
    vars:
    q:
  • ‘abc’
  • 123
    tasks:
  • debug:
    msg: >-
    {{ q is search(‘abc\t’) }}

This returns false. I have tried different variations of the regex, but nothing worked. Is this possible to do?

Escape the tab with another single quote, like this:

             {{ q is search('abc\\t') }}

Dick

On 2022-06-20 (Mon) 13:52, Dick Visser w

Escape the tab with another single quote, like this:

I meant with another backslash obviously

    q:
      - 'abc<tab character here>'
      - 123

    - debug:
        msg: >-
          {{ q is search('abc\t') }}

There are more aspects to this question:

* It's necessary to understand the difference between 'Double-Quoted
  Style' and 'Single-Quoted Style'. See
https://yaml.org/spec/1.2.2/#731-double-quoted-style
https://yaml.org/spec/1.2.2/#732-single-quoted-style

In 'Single-Quoted Style' only "'" has to be escaped. As a result, the
string 'abc\t' doesn't include TAB. It's a sequence of characters: a,
b, c, \, t. Test it. The task below

    - copy:
        dest: /tmp/test.txt
        content: |
          {{ ql.0 }}
          {{ ql.1 }}
      vars:
        ql:
          - 'abc\tx'
          - 123

gives

  > cat /tmp/test.txt
  abc\tx
  123

The string will include TAB if you use 'Double-Quoted Style'

    - copy:
        dest: /tmp/test.txt
        content: |
          {{ ql.0 }}
          {{ ql.1 }}
      vars:
        ql:
          - "abc\tx"
          - 123

gives

  > cat /tmp/test.txt
  abc x
  123

* The *search* test doesn't work with lists. It works with strings.
  See
https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html#testing-strings

Use it to test a single item of a list. For example,

    - debug:
        msg: "{{ ql.0 is search(regex) }}"
      vars:
        regex: 'abc\tx'
        ql:
          - "abc\tx"
          - 123

gives

  msg: true

Also the task below, with single-quoted *item* and escaped backslash
in *regex*, gives the same result

    - debug:
        msg: "{{ ql.0 is search(regex) }}"
      vars:
        regex: 'abc\\tx'
        ql:
          - 'abc\tx'
          - 123

* Instead, you can "Test if a list contains a value". See
https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html#testing-if-a-list-contains-a-value

For example, both tasks below returns *True*

    - debug:
        msg: "{{ item in ql }}"
      vars:
        item: 'abc\tx'
        ql:
          - 'abc\tx'
          - 123

    - debug:
        msg: "{{ item in ql }}"
      vars:
        item: "abc\tx"
        ql:
          - "abc\tx"
          - 123

* If you want to use *regex* to test an item in a list use *select*.
  For example,

    - debug:
        msg: "{{ ql|select('search', regex) }}"
      vars:
        regex: 'abc\\tx'
        ql:
          - 'abc\tx'
          - 123

gives

  msg:
    - abc\tx

, or use it in a condition. For example,

    - debug:
        msg: "Regex {{ regex }} is present in the list."
      when: ql|select('search', regex)|length > 0
      vars:
        regex: 'abc\\tx'
        ql:
          - 'abc\tx'
          - 123

gives

  msg: Regex abc\\tx is present in the list.

Thank you for your replies. The search test does work with lists and this is where the
issue lies. Your examples helped me clear this up. The search, regex, etc tests will

convert the object to a string. In python code, this means that the list will be turned
into a string with str(list_here). This will escape tab characters in the list items, so

that a list [“a”, “b\t”] will get converted to the string, ‘[“a”, “b\t”]’. To match this correctly
with the search test, I need to search for …b\t… in single quotes.

There is also the case that the search test appears in an assert:

  • assert:
    that:
  • q is search(‘abc\t’)

The tab character needs to be double escaped here because (I think)
the assert clause is interpreted as a double quoted string.

Correction:

  • assert:
    that:

  • q is search(‘abc\t’ | regex_escape)

using regex_escape to avoid escaping manually the backslashes (‘abc\\t’)

I see. You're right. It's worth to test the escaping. The simplest
case is when the items are double-quoted and *regex* is variable

    - debug:
        msg: "{{ _list is search(regex) }}"
      vars:
        _list: ["a", "b\t"]
        regex: 'b\\t'

Additional escaping, because of the outside double-quotes, is needed
when *regex* is value

    - debug:
        msg: "{{ _list is search('b\\\\t') }}"
      vars:
        _list: ["a", "b\t"]

Additional escaping is also needed when the items are single-quoted
and *regex* is variable. This time because of '\\' is needed after
evaluation

    - debug:
        msg: "{{ _list is search(regex) }}"
      vars:
        _list: ['a', 'b\t']
        regex: 'b\\\\t'

Finally, one more additional escaping is needed when you put the
*regex* as a value

    - debug:
        msg: "{{ _list is search('b\\\\\\\\t') }}"
      vars:
        _list: ['a', 'b\t']

All tasks above return True.

This overview is worthy of its own paragraph in the ansible docs!