Search code examples
variablesansiblegrepdefault

detect desired grep on server using Ansible


My requirement is to use grep -E option in Ansible.

I wish to first use /usr/xpg4/bin/grep if it is present on the server else switch to /bin/grep

I'm looking for a POSIX solutions that works on various shells and operating systems.

Below command works fine on command-line:

$ ls /usr/xpg4/bin/grep 2> >(grep -v 'No such file or directory' >&2) || ls /bin/grep 2> >(grep -v 'No
> such file or directory' >&2)

Output:

/usr/xpg4/bin/grep

I tried using the above solution in Ansible like below:

 - name: "Detect the grep on the system"
   ignore_errors: yes
   command:  "ls /usr/xpg4/bin/grep 2> >(grep -v 'No such file or directory' >&2) || ls /bin/grep 2> >(grep -v 'No     such file or directory' >&2 | head -1"
   register: grepfound

In the output it finds both the grep and instead of getting one single preferred /usr/xpg4/bin/grep {{ grepfound.stdout }} prints both the grep which I never wanted.

Output:

fatal: [localhost]: FAILED! => {"changed": true, "cmd": ["ls", "/usr/xpg4/bin/grep", "2>", ">(grep", "-v", "No such file or directory", ">&2)", "||", "ls", "/bin/grep", "2>", ">(grep", "-v", "No such file or directory", ">&2"], "delta": "0:00:00.013219", "end": "2021-06-14 05:25:52.178385", "msg": "non-zero return code", "rc": 2, "start": "2021-06-14 05:25:52.165166", "stderr": "2>: No such file or directory\n>(grep: No such file or directory\n-v: No such file or directory\nNo such file or directory: No such file or directory\n>&2): No such file or directory\n||: No such file or directory\nls: No such file or directory\n2>: No such file or directory\n>(grep: No such file or directory\n-v: No such file or directory\nNo such file or directory: No such file or directory\n>&2: No such file or directory", "stderr_lines": ["2>: No such file or directory", ">(grep: No such file or directory", "-v: No such file or directory", "No such file or directory: No such file or directory", ">&2): No such file or directory", "||: No such file or directory", "ls: No such file or directory", "2>: No such file or directory", ">(grep: No such file or directory", "-v: No such file or directory", "No such file or directory: No such file or directory", ">&2: No such file or directory"], **"stdout": "/bin/grep\n/usr/xpg4/bin/grep"**, "stdout_lines": ["/bin/grep", "/usr/xpg4/bin/grep"]}
...ignoring

I tried using {{ grepfound.stdout_lines[0] }} as a workaround but as you see it prints /bin/grep instead of /usr/xpg4/bin/grep. And if i use {{ grepfound.stdout_lines[1] }} it will work here but fail where only one grep is found.


Solution

  • I would have still liked your help use stdout_lines instead of stdout so that the processes show up better formatted segregated... each process in a new-line

    That is where | select comes into play -- it is designed to filter items of a list where the jinja2 test evaluates to true

    - set_fact:
       example_data:
         stdout_lines:
         - 1111 nothing here
         - 2222 this one is httpd
         - 3333 this one is tomcat
         - 4444 again nothing
    - debug:
        msg: |
          the things as a list are:
          {{ example_data.stdout_lines | select('search', '(tomcat|weblogic|httpd)') | list }}
    
          but you can also fold them back into one str:
          {{ example_data.stdout_lines | select('search', '(tomcat|weblogic|httpd)') | join(nl) }}
      vars:
        # this silliness is to work around a quirk of jinja2 where
        # | join("\n") literally uses `"\n"` to join items :-(
        nl: "\n"
    

    produces

      msg: |-
        the things as a list are:
        ['2222 this one is httpd', '3333 this one is tomcat']
    
        but you can also fold them back into one str:
        2222 this one is httpd
        3333 this one is tomcat