# Wildcard or Glob option in Ansible variables

**URL:** <https://forum.ansible.com/t/wildcard-or-glob-option-in-ansible-variables/11010>\
**Category:** Get Help\
**Created:** [November 20, 2024, 2:44am UTC](https://forum.ansible.com/t/wildcard-or-glob-option-in-ansible-variables/11010 "2024-11-20T02:44:17Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![anoopv89](https://avatars.discourse-cdn.com/v4/letter/a/5fc32e/32.png) [@anoopv89](https://forum.ansible.com/u/anoopv89)\
**Post date:** [November 20, 2024, 2:44am UTC](https://forum.ansible.com/t/wildcard-or-glob-option-in-ansible-variables/11010/1 "2024-11-20T02:44:17Z")

</div>

I’m trying to install a set of services on my Linux boxes and have to start the services using Ansible Playbook as well.

The issue is that when I install a package the service name of that particular package comes with the version number, so I want to create a play that can start the service regardless of the version that is getting installed on the machine.

I have defines the packages and service names in a group\_vars file and used the below option

start-services:  
- service1  
- service2  
- service\*-3  
But this is not working, so can someone please help me with this?

Thanks,

---

<div class="post-metadata">

**Author:** ![chris](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/chris/32/293_2.png) [@chris](https://forum.ansible.com/u/chris)\
**Post date:** [November 22, 2024, 4:54pm UTC](https://forum.ansible.com/t/wildcard-or-glob-option-in-ansible-variables/11010/2 "2024-11-22T16:54:39Z")

</div>

I think you probably need to write a task to find the name of the service, including the version number and then start them.

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [November 24, 2024, 7:35pm UTC](https://forum.ansible.com/t/wildcard-or-glob-option-in-ansible-variables/11010/3 "2024-11-24T19:35:13Z")

</div>

Challenge accepted! 🤪 This turns out to be tricky to do right, but I think this works pretty well.

Let’s assume the system uses systemd service units. The `systemctl` command provides a `show` command which takes globs and lists matching systemd _units_ – not just _service_ units. Thus:

```
$ systemctl show '*' --property=Names --all --value --no-pager

```

The “`--all`” flag is necessary to include those units not currently loaded. A couple of extra flags – “`--property=Names --value`” – make it produce output suitable for consumption by scripts rather than humans. But even then there are complications:

- Some units have multiple names. For example, on my system “`ModemManager.service`” is also known as “`dbus-org.freedesktop.ModemManager1.service`.” Likewise, “`multi-user.target`” is also called “`runlevel3.target`,” “`runlevel4.target`,” and “`runlevel2.target`.” These names get listed on the same line with a space between them, so that must be dealt with.

- Some unit names have backslash-escaped hex codes in their names. `systemctl` conveniently double-quotes such names that would need quoting to be re-used in scripts.For example,  

- For reasons I don’t understand, `systemctl` likes to include extra (well, _I_ feel they’re extra) blank lines in its output. Those need to be discarded without data loss.

With all that said, here’s my attempt at a task to find systemd service names which match a set of glob patterns. Beware: this is set up to take a list of globs, even if that list has only one glob. Interpreting the registered output would require some changes were you to run the task once without “`loop:`.” I’ve tried to make it handle the general case.

```yaml
---
# anoopv89_01.yml
- name: Systemd units via globs
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Determine systemd units matching a list of globs
      register: unit_globs
      args:
        executable: /bin/bash
      loop:
        - '*' # Matches all units, not just services
        - '[aeiou]*.service' # Only services starting with a vowel
        - 'autosi*' # Matches my custom 'autosig.service'.
      loop_control:
        loop_var: glob
      vars:
        action: none # Only used in a comment below, but still must be defined.
                     # You would also need to 'become' if this were, say, 'start'.
      ansible.builtin.shell: |
        unquote() {
          # This is nuts: we need to remove the quotes (which the 'eval' does).
          # But we also need to preserve each backslash in the
          # json going to stdout, so we have to double them here in the yaml.
          eval "printf \"%s\" ${1//\\/\\\\}"
        }
        declare -a primaries=()
        while read -r primary alternates; do
          if [-n "$primary"] ; then # Some lines will be blank!
            # If you wanted to take action on each service, here is where
            # to do it, sending output to stderr since we are printing JSON
            # to stdout, like this:
            # eval "systemctl {{ action }} $primary" >&2
            # Note: systemctl quotes $primary if quotes are needed,
            # so do not quote $primary in the above eval expression.
            primaries+=( "\"$(unquote "$primary")\"" )
          fi
        done < <( systemctl show '{{ glob }}' --all --property=Names --value )
        printf "{\"%s\": [" "{{ glob }}"
        IFS=$', \t\n'; printf "%s" "${primaries[*]}"
        printf "]}"

    - name: Reinterpret registered results stdout as json
      # This could be a set_fact instead.
      ansible.builtin.debug:
        msg: '{{ unit_globs.results | map(attribute="stdout") | map("from_json") }}'

```

On my system, that set of globs produces the following output, slightly edited and annotated for clarity:

```plaintext
ok: [localhost] => 
  msg:
# It's a list of dicts with the globs as keys and the list of matching
# primary unit names as values. (Alternate names are excluded.)
  - '*': # This glob will match all units
    - sys-fs-fuse-connections.mount
    - rpc_pipefs.target
    - network-pre.target
    - systemd-ask-password-plymouth.path
    - sys-devices-virtual-misc-rfkill.device
    - systemd-user-sessions.service
      [… skipping ahead a bit …]
    - sshd.service
    - sys-subsystem-net-devices-virbr0.device
    - veritysetup.target
    - systemd-udevd-kernel.socket
    - abrt-journal-core.service
    - system-dbus\x2d:1.3\x2dorg.freedesktop.problems.slice
    - systemd-sysctl.service
    - systemd-logind.service
      [… still skipping …]
    - bluetooth.service
    - uresourced.service
    - sys-devices-pci0000:00-0000:00:1d.4-0000:07:00.0-nvme-nvme0-nvme0n1-nvme0n1p1.device
    - system.slice
      [… more skipping …]
    - httpd.service
    - system-systemd\x2dzram\x2dsetup.slice
    - logwatch.timer
    - gssproxy.service
      [… there are a lot of systemd units! …]
    - systemd-network-generator.service
    - avahi-daemon.socket
    - systemd-tmpfiles-setup-dev.service
    - lightdm.service

  - '[aeiou]*.service': # the glob that matches service names beginning with a vowel.
    - abrt-xorg.service
    - abrt-journal-core.service
    - uresourced.service
    - initial-setup.service
    - accounts-daemon.service
    - earlyoom.service
    - atd.service
    - upower.service
    - alsa-state.service
    - abrt-oops.service
    - irqbalance.service
    - abrtd.service
    - autosig.service
    - user-runtime-dir@12428.service
    - avahi-daemon.service
    - udisks2.service
    - auditd.service
    - user@12428.service

  - autosi*: # This service rotates my email signature quip.
    - autosig.service

```

Maybe someone will find this useful. I sure learned a lot.

---

<div class="post-metadata">

**Author:** ![chris](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/chris/32/293_2.png) [@chris](https://forum.ansible.com/u/chris)\
**Post date:** [November 24, 2024, 8:00pm UTC](https://forum.ansible.com/t/wildcard-or-glob-option-in-ansible-variables/11010/4 "2024-11-24T20:00:00Z")

</div>

I’d use the [ansible.builtin.service\_facts module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_facts_module.html), to save using `shell`, if possible…

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [November 24, 2024, 9:35pm UTC](https://forum.ansible.com/t/wildcard-or-glob-option-in-ansible-variables/11010/5 "2024-11-24T21:35:33Z")

</div>

Good to know about, that module.

I’ve never bought into the “avoid the shell” mantra, but I see where it comes from.

I’ve been looking around for something in Ansible that exposes `fnmatch()` (i.e. glob pattern matching) outside of a files-in-a-directory context, and I’m kind of surprised it’s not there. I would use a regex instead, but that’s not the original question.
