Here’s a 5-minute tutorial on the Ansible command
module, which Level Up considers one of the first 10 Ansible modules you should know. We also explain how command
compares and contrasts with the related shell
and raw
modules.
What is the Ansible Command Module?
As its name would suggest, the command
module helps you execute basic commands on remote Linux hosts. (For Windows hosts, you can use the similar win_command module.) However, it’s more limited than you might think at first glance, and may not always be what you need (see below for details on alternatives like shell
[similar to the win_shell module] and raw
). But leveraging the command
module is a straightforward and effective way for you to perform CLI tasks that do not require advanced scripting or shell-specific features.
Here’s an example of using the command module in a playbook:
# run-command.yml:
---
- name: Run a command
hosts: all
gather_facts: false
vars:
cmd: "uptime"
tasks:
- name: "Run command {{ cmd }}"
ansible.builtin.command:
cmd: "{{ cmd }}"
register: cmd_result
- name: "Print {{ cmd }} result"
ansible.builtin.debug:
msg: "{{ cmd_result.stdout_lines }}"
Beyond the absolute basics, we’ve included a couple of ideas in this playbook to help you see how easy it is to 1) effortlessly reuse your playbook for different commands in the future and 2) get exactly the output you care about.
Example output:
$ ansible-playbook run-command.yml
PLAY [Run a command] ***************************************************************************************************
TASK [Run command uptime] **********************************************************************************************
changed: [localhost]
TASK [Print uptime result] *********************************************************************************************
ok: [localhost] => {
"msg": [
"10:52 up 1 day, 3:24, 3 users, load averages: 2.15 2.62 2.55"
]
}
PLAY RECAP *************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$
- By variabilizing the “cmd” near the top of the playbook, you can change it in one place in your playbook and have it apply everywhere (or override it via an extra-var).
- By using that Ansible workhorse of printing things to the screen, the
debug
module, to output only the “stdout_lines” part of the JSON data structure that came back from the command module, you are removing unnecessary details and getting right to the point.
Comparing and Contrasting the command
, shell
, and raw
Modules
At the highest level, these things are true:
command
: Runs arbitrary commands but not using a shell.
2) shell
: Runs arbitrary commands using a shell.
3) raw
: Runs arbitrary commands directly over your network transport (e.g., SSH) without using Python on the remote host.
Going a bit deeper…
The command
Module
- Executes commands without involving a shell. It is the recommended module for simple tasks that do not require any shell features or piping.
Pros:
- Fast and considered more secure because it avoids shell-specific vulnerabilities.
- Perhaps easier to understand and maintain, because it doesn’t involve complex shell scripting.
Cons:
- Limited to simple commands without shell-specific features, like piping, redirects, or environment variable substitution.
The shell
Module
- Allows you to execute shell commands with advanced shell features such as pipes, redirects, and environment variable substitution.
Pros:
- Offers more flexibility than
command
for complex CLI tasks that may require advanced shell features.
Cons:
- Potentially less secure than
command
due to potential shell injection vulnerabilities. - Can end up being harder to read (and therefore maintain as code), precisely because it allows complex shell scripting (which you might be better off fully Ansibilizing instead).
The raw
Module
- Executes commands directly on the target system without any (Python-based) module processing. It is useful when working with systems that do not and cannot have Python installed.
Pros:
- Can be used on systems without Python (e.g., your network devices).
- Can be useful provisioning new systems with Ansible (e.g., bare metal or pre-boot interactions).
Cons:
- Little to no error handling or reporting from Ansible– unlike nearly all other interactions that Ansible has with the hosts it automates, when you use
raw
, you are basically just sending a command over the network and hoping for the best. - Lacks the Ansible’s usual declarative/idempotent features (and often related security/error handling) provided by the command and shell modules.
Wrapping Up
In the last few minutes together, we just demoed and covered the basics of the Ansible command
module, one of the first 10 Ansible modules you should know, and highlighted its key comparison points with the shell
and raw
modules. For simple tasks that do not require advanced shell features, the command module is probably going to be your best bet. For your more complex CLI tasks, the shell
module provides you with additional functionality, but at the risk of some potential security downsides. And the raw
module is probably best kept in your back pocket for systems without Python (like your networking gear, and when no collections or modules already support what you are trying to do with that gear), or when provisioning brand-new hosts via Ansible from the datacenter rack, up.