I just want to update this old discussion to point out that there is now a package module that makes this more straightforward

- name: get the rpm or apt package facts
  package_facts:
    manager: "auto"

- name: show apache2 version
  debug: var=ansible_facts.packages.apache2[0].version
Answer from fred on Stack Overflow
🌐
Ansible
docs.ansible.com › projects › ansible › latest › collections › ansible › builtin › package_facts_module.html
ansible.builtin.package_facts module – Package information as facts — Ansible Community Documentation
Return information about installed packages as facts. The below requirements are needed on the host that executes this module. See details per package manager in the manager option. - name: Gather the package facts ansible.builtin.package_facts: manager: auto - name: Print the package facts ansible.builtin.debug: var: ansible_facts.packages - name: Check whether a package called foobar is installed ansible.builtin.debug: msg: "{{ ansible_facts.packages['foobar'] | length }} versions of foobar are installed!" when: "'foobar' in ansible_facts.packages"
🌐
Reddit
reddit.com › r/ansible › check if package is installed
r/ansible on Reddit: Check if package is installed
June 5, 2023 -

What is the best way to have ansible check if cabon black package had been installed and if not run to few steps. Install dependencies instal lcabon black and activate it. Finaly star and enable service. This for linux os

Discussions

ansible - How can I check for an installed packaged version on multiple linux hosts? - DevOps Stack Exchange
I searched all day for different options without luck. Attached is the output of ansible-playbook. Any hints guys? --- - hosts: centos become: true tasks: - name: Check Hostname command: /usr/bin/hostname - name: Check for package if is installed yum: list: snapd register: result More on devops.stackexchange.com
🌐 devops.stackexchange.com
February 18, 2019
Check if a package (RPM) is installed in a certain version
Hi, I’m currently writing a playbook for a workstation running Rocky Linux, and I can’t figure out one detail. I want to add a line to a file (yum.conf) only when the vagrant package is installed in version 2.4.1. I know I have to use the package_facts module to do this. More on forum.ansible.com
🌐 forum.ansible.com
4
0
February 19, 2025
Access ansible facts variable?
Hi, I’m currently writing an Ansible playbook, and I can’t seem to wrap my head around one small problem. I’m trying to check if the vagrant package is installed in version 2.4.1. As far as I can tell, I need the package_facts module to do this. I’m testing this in my playbook like ... More on forums.rockylinux.org
🌐 forums.rockylinux.org
3
0
February 19, 2025
yum - how to verify that OS packages are removed or not installed in ansible - Stack Overflow
So I am writing an ansible playbook ... and then checks if they were uninstalled. Uninstallation is not the problem (it works fine), but I need to verify if the packages were really uninstalled and then do some other stuff depending on that. This is on RedHat 6.9 machine, and I am using Ansible 2.6. - name: list installed ABRT packages ... More on stackoverflow.com
🌐 stackoverflow.com
🌐
DEV Community
dev.to › koh_sh › how-to-do-if-a-package-is-installed-do-something-with-ansible-3fhi
How to do "if a package is installed, do something" with Ansible - DEV Community
June 14, 2020 - tasks: - name: check if httpd is installed shell: rpm -qa | grep httpd register: httpd_installed ignore_errors: True check_mode: False changed_when: False - name: print debug: msg: "httpd is installed" when: httpd_installed.rc == 0 · But this is a little bit of trouble when you use it many times. Extra parameters like changed_when or ignore_errors should be set · Warnings may be thrown at running Playbook or ansible-lint
🌐
OneUptime
oneuptime.com › home › blog › how to use ansible package_facts to list installed packages
How to Use Ansible package_facts to List Installed Packages
February 21, 2026 - After running this task, the ansible_facts.packages variable contains a dictionary where keys are package names and values are lists of installed versions (a list because you can have multiple versions of the same package installed in some cases). The most common use case is checking whether a particular package exists on the system before performing an action. # Check if nginx is installed and act accordingly - name: Gather package facts ansible.builtin.package_facts: manager: auto - name: Display nginx version if installed ansible.builtin.debug: msg: "nginx version: {{ ansible_facts.packages['nginx'][0].version }}" when: "'nginx' in ansible_facts.packages" - name: Warn if nginx is not installed ansible.builtin.debug: msg: "nginx is NOT installed on this host" when: "'nginx' not in ansible_facts.packages"
🌐
LabEx
labex.io › questions › how-to-check-if-a-package-is-successfully-installedupdatedremoved-using-ansible-289651
How to Verify Package Status in Ansible | LabEx
September 19, 2024 - Updating a package follows a similar approach, but you'll want to check the changed attribute to see if the package was actually updated: - name: Update package package: name: nginx state: latest register: package_update - name: Check package update status debug: msg: "Package updated successfully" when: package_update.changed · In this case, the state: latest parameter ensures that the latest version of the package is installed, and the changed attribute will be set to true if the package was updated.
🌐
Stack Exchange
devops.stackexchange.com › questions › 6404 › how-can-i-check-for-an-installed-packaged-version-on-multiple-linux-hosts
ansible - How can I check for an installed packaged version on multiple linux hosts? - DevOps Stack Exchange
February 18, 2019 - ansible -i <inventory> <target group, lets' say some CentOS systems> -m shell -a "rpm -qa | grep <package name>" That would display a list consisting of server name and package version.
🌐
DEV Community
dev.to › setevoy › ansible-check-if-a-package-installed-on-a-remote-system-4402
Ansible: check if a package is installed on a remote system - DEV Community
March 10, 2019 - $ cat is-package-installed.yml - name: Check to see if a package is installed hosts: "{{ hosts | default('localhost') }}" tasks: - name: Gather the packager facts package_facts: - name: Package status debug: msg: "{{ item }} {{ 'installed' if ...
Find elsewhere
🌐
Ansible
forum.ansible.com › get help
Check if a package (RPM) is installed in a certain version - Get Help - Ansible
February 19, 2025 - Hi, I’m currently writing a playbook for a workstation running Rocky Linux, and I can’t figure out one detail. I want to add a line to a file (yum.conf) only when the vagrant package is installed in version 2.4.1. I know I have to use the package_facts module to do this.
🌐
Rocky Linux Forum
forums.rockylinux.org › rocky linux help & support
Access ansible facts variable? - Rocky Linux Help & Support - Rocky Linux Forum
February 19, 2025 - Hi, I’m currently writing an Ansible playbook, and I can’t seem to wrap my head around one small problem. I’m trying to check if the vagrant package is installed in version 2.4.1. As far as I can tell, I need the package_facts module to do this. I’m testing this in my playbook like this: - name: Gather package facts ansible.builtin.package_facts: manager: rpm - name: Print Vagrant package facts ansible.builtin.debug: var: ansible_facts.packages['vagrant'] When I run the playboo...
🌐
ComputingForGeeks
computingforgeeks.com › home › ansible check if software package is installed on linux
Ansible check if software package is installed on Linux
March 21, 2026 - servers #connection: local # When running locally vars: package_names: - vim tasks: - name: "Check if listed package is installed or not on Debian Linux family" command: dpkg-query -l "{{ item }}" loop: "{{ package_names }}" register: package_check ...
🌐
GitHub
github.com › khomutoff › rpm_check
GitHub - khomutoff/rpm_check: Module for Ansible to check if rpm package installed on your system. · GitHub
To use the rpm_check module just copy the file into ./library, alongside your top level playbooks, or copy it into the path specified by ANSIBLE_LIBRARY or the --module-path command line option.
Author   khomutoff
🌐
Ansible
docs.ansible.com › projects › ansible › latest › collections › ansible › builtin › package_module.html
ansible.builtin.package module – Generic OS package manager — Ansible Community Documentation
This modules manages packages on a target without specifying a package manager module (like ansible.builtin.dnf, ansible.builtin.apt, …). It is convenient to use in an heterogeneous environment of machines without having to create a specific task for each package manager. ansible.builtin.package calls behind the module for the package manager used by the operating system discovered by the module ansible.builtin.setup. If ansible.builtin.setup was not yet run, ansible.builtin.package will run it.
Top answer
1 of 1
3

Use the module package_facts. You'll get a dictionary of installed packages in the variable ansible_facts.packages. For example,

    - package_facts:
    - debug:
        msg: "{{ ansible_facts.packages[item]|
                 map(attribute='version') }}"
      loop:
        - firefox
        - libwebp6
        - thunderbird
      when: ansible_facts.packages[item] is defined

gives in Ubuntu

ok: [localhost] => (item=firefox) => 
  msg:
  - 88.0.1+build1-0ubuntu0.20.04.2
ok: [localhost] => (item=libwebp6) => 
  msg:
  - 0.6.1-2
ok: [localhost] => (item=thunderbird) => 
  msg:
  - 1:78.8.1+build1-0ubuntu0.20.04.1

The results are lists because more versions of a package might be installed. If you want to take the first items add the filter first to the pipe

    - debug:
        msg: "{{ ansible_facts.packages[item]|
                 map(attribute='version')|first }}"
      ...

If you put the list of the packages into a variable. For example,

  packages: [firefox, libwebp6, thunderbird]

you can declare the dictionary package_versions

  package_versions: "{{ dict(packages|
                             zip(packages|
                                 map('extract', ansible_facts.packages)|
                                 map('map', attribute='version'))) }}"

gives

  package_versions:
    firefox:
    - 88.0.1+build1-0ubuntu0.20.04.2
    libwebp6:
    - 0.6.1-2
    thunderbird:
    - 1:78.8.1+build1-0ubuntu0.20.04.1

Example of a complete playbook for testing

- hosts: localhost

  vars:

    packages: [firefox, libwebp6, thunderbird]

    package_versions: "{{ dict(packages|
                               zip(packages|
                                   map('extract', ansible_facts.packages)|
                                   map('map', attribute='version'))) }}"

  tasks:

    - package_facts:

    - debug:
        msg: "{{ ansible_facts.packages[item]|
                 map(attribute='version')|first }}"
      loop:
        - firefox
        - libwebp6
        - thunderbird
      when: ansible_facts.packages[item] is defined

    - debug:
        var: package_versions
Top answer
1 of 2
4

ansible_facts.packages is a dictionary. There are no keys in that dictionary named OB2* nor OB2 since no package has this exact name.

If you want to get all keys which names start with the string "OB2", one way is to filter out all others.

  • Transform you dict to a key/value list with the dict2items filter
  • Use the selectattr filter and apply the match test to find the relevant entries.
  • Since the key name is also contained in the parameter name inside each element in the value list , you can retain only the value using the map(attribute='someattr') filter
  • Last, flatten the list to get one single list containing all packages version

Here is a playbook illustrating the concept. For the example, I used as a prefix "zlib". Just change it back to whatever suits your needs

 ---
 - hosts: localhost
   gather_facts: false
 
   vars:
     package_prefix: "zlib"
 
     filtered_packages: "{{ ansible_facts.packages | dict2items 
       | selectattr('key', 'match', package_prefix) 
       | map(attribute='value') | flatten }}"
 
   tasks:
     - name: gather package facts
       ansible.builtin.package_facts:
 
     - name: debug the raw variable
       debug:
         var: filtered_packages
 
     - name: count relevant packages
       vars:
         pkg_num: "{{ filtered_packages | count }}"
       debug:
         msg: "There are {{ pkg_num }} packages
           which name starts with {{ package_prefix }}"
 
     - name: show some info about relevant packages
       debug:
         msg: "Package named {{ item.name }} is in category {{ item.category }}
           and has version {{ item.version }}"
       loop: "{{ filtered_packages }}"

Which gives on my Ubuntu local machine:

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

TASK [gather package facts] ******************************************************************************************************
ok: [localhost]

TASK [debug the raw variable] ****************************************************************************************************
ok: [localhost] => {
    "filtered_packages": [
        {
            "arch": "amd64",
            "category": "libs",
            "name": "zlib1g",
            "origin": "Ubuntu",
            "source": "apt",
            "version": "1:1.2.11.dfsg-2ubuntu1.3"
        },
        {
            "arch": "amd64",
            "category": "libdevel",
            "name": "zlib1g-dev",
            "origin": "Ubuntu",
            "source": "apt",
            "version": "1:1.2.11.dfsg-2ubuntu1.3"
        }
    ]
}

TASK [count relevant packages] ***************************************************************************************************
ok: [localhost] => {
    "msg": "There are 2 packages which name starts with zlib"
}

TASK [show some info about relevant packages] ************************************************************************************
ok: [localhost] => (item={'name': 'zlib1g', 'version': '1:1.2.11.dfsg-2ubuntu1.3', 'arch': 'amd64', 'category': 'libs', 'origin': 'Ubuntu', 'source': 'apt'}) => {
    "msg": "Package named zlib1g is in category libs and has version 1:1.2.11.dfsg-2ubuntu1.3"
}
ok: [localhost] => (item={'name': 'zlib1g-dev', 'version': '1:1.2.11.dfsg-2ubuntu1.3', 'arch': 'amd64', 'category': 'libdevel', 'origin': 'Ubuntu', 'source': 'apt'}) => {
    "msg": "Package named zlib1g-dev is in category libdevel and has version 1:1.2.11.dfsg-2ubuntu1.3"
}

PLAY RECAP ***********************************************************************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
2 of 2
4

You have to filter the keys, a direct address is not possible, because you don't know the exact name.

- name: Gather the package facts
  ansible.builtin.package_facts:

- name: Filter package names
  set_fact:
    filtered_package_names: "{{ ansible_facts.packages | list 
      | map('regex_search', '^vim.*') | select('string') | list }}"
  
- name: Print filtered packages
  debug:
    var: filtered_package_names

- name: Print package details from all filtered packages
  debug:
    msg: "{{ ansible_facts.packages[item] }}"
  with_items: "{{ filtered_package_names }}"

With list a list of the keys is created, then you can filter this list with regex_search, afterwards the list is reduced to the filter result.

== Edit begin

There is a smarter filter method. Instead of using map(regex_search) / select(string), you could use directly select(match), so the filtering would look like:

- name: Filter package names
  set_fact:
    filtered_package_names: "{{ ansible_facts.packages | list 
      | select('match', '^vim.*') | list }}"

== Edit end

The result is a list of package names that match your regex.

If you need more information about one of the packages, you can then use ansible_facts.packages[_your_item] to get the rest of the information.

Example output of the above tasks:

TASK [Gather the package facts] ****************************************************************************************
ok: [localhost]

TASK [Filter package names] ********************************************************************************************
ok: [localhost]

TASK [Print filtered packages] *****************************************************************************************
ok: [localhost] => {
    "filtered_package_names": [
        "vim",
        "vim-common",
        "vim-runtime",
        "vim-tiny"
    ]
}

TASK [Print package details] *******************************************************************************************
ok: [localhost] => (item=vim) => {
    "msg": [
        {
            "arch": "amd64",
            "category": "editors",
            "name": "vim",
            "origin": "Ubuntu",
            "source": "apt",
            "version": "2:8.1.2269-1ubuntu5.7"
        }
    ]
}
ok: [localhost] => (item=vim-common) => {
    "msg": [
        {
            "arch": "all",
            "category": "editors",
            "name": "vim-common",
            "origin": "Ubuntu",
            "source": "apt",
            "version": "2:8.1.2269-1ubuntu5.7"
        }
    ]
}
ok: [localhost] => (item=vim-runtime) => {
    "msg": [
        {
            "arch": "all",
            "category": "editors",
            "name": "vim-runtime",
            "origin": "Ubuntu",
            "source": "apt",
            "version": "2:8.1.2269-1ubuntu5.7"
        }
    ]
}
ok: [localhost] => (item=vim-tiny) => {
    "msg": [
        {
            "arch": "amd64",
            "category": "editors",
            "name": "vim-tiny",
            "origin": "Ubuntu",
            "source": "apt",
            "version": "2:8.1.2269-1ubuntu5.7"
        }
    ]
}
🌐
GitHub
github.com › ansible › ansible › issues › 83088 › linked_closing_reference
Need ansible.builtin.dpkg_selections to hold package even if not already installed · Issue #83087 · ansible/ansible
April 18, 2024 - - name: Hold selected package(s) Ubuntu 22 and above ansible.builtin.dpkg_selections: name: "{{ item }}" selection: hold with_items: "{{ base_pkg_setup_apt_pkg_hold }}" when: - ansible_facts['distribution'] == "Ubuntu" - ansible_facts['distribution_major_version'] >= "22" - "item not in held_packages.stdout_lines" I expect the package python2.7-minimal to be held even if it's not installed, similar to how apt-mark hold python2.7-minimal works.
Author   ansible
🌐
Waylon Walker
waylonwalker.com › ansible-install-if-not-callable
Installing packages with ansible only if they do not exist
December 24, 2021 - re-installing a bunch of things ... this I have been following this pattern. check if the command is installed with command -v <command>...
🌐
DevPress
devpress.csdn.net › cicd › 62eb6b7720df032da732b2e0.html
Ansible: check if a package is installed on a remote system_linux_weixin_0010034-CI/CD
August 4, 2022 - Before running the Let’s Encrypt client to obtain a new certificate – need to check if NGINX is installed on a remote host. ... ... - name: "NGINX test result" debug: msg: "NGINX found" when: "'nginx' in ansible_facts.packages" - name: "NGINX test result" debug: msg: "NGINX NOT found" when: "'nginx' not in ansible_facts.packages"