Ansible command Module Tutorial + Examples


Percy Grunwald's Profile Picture

Written by Percy Grunwald

— Last Updated March 2, 2024

Ansible Course: Productive with Ansible (2024)
Ansible Course: Productive with Ansible (2024)
Go from Ansible beginner to Ansible pro with this full video course.

What does the Ansible command module do?

Ansible’s command module executes simple shell commands on remote hosts.

- name: precompile assets with asdf in $PATH and $RAILS_ENV set to production
  command: "rails assets:precompile"
  args:
    chdir: /opt/my_app
  environment:
    PATH: "/opt/asdf/bin:/opt/asdf/shims:{{ ansible_env.PATH }}"
    RAILS_ENV: production

Ansible command Module Video Tutorial

If you prefer watching to reading, here’s a full video tutorial from the TopTechSkills YouTube channel covering a many of the points and examples from this article. Feel free to comment on this article or the video if you have any questions.

▶️ Watch on YouTube

When to use the command module vs shell module

The command and shell modules are almost identical, except that command cannot use special shell operators such as < > | ; & or access user-specific environment variables like $HOME. According to the docs, the command module is more secure and predictable, so my personal preference is to default to using command unless I need the extended functionality of shell.

# If your command looks like this, use `command`:
/path/to/program arg1 arg2

# If your command looks like this, use `shell`:
java -version 2>&1 | grep OpenJDK

Examples

How to run command only if a file doesn’t exist

Use the creates argument to run the command only if a file doesn’t exist already.

- name: create a new test file only if it doesn't already exist
  command: touch /tmp/test_file
  args:
    creates: /tmp/test_file

How to run command only if a file does exist

Use the removes argument to run the command only if a file already exists.

- name: remove /tmp/test_file only if it already exists
  command: rm /tmp/test_file
  args:
    removes: /tmp/test_file

How to run command in a different directory

Use the chdir argument to run command inside the specified directory.

- name: precompile assets after changing to the app directory
  command: "rails assets:precompile"
  args:
    chdir: /opt/my_app

How to run command with custom environment variables

Use the environment keyword to set environment variables for the command. This is commonly used to alter the $PATH or set framework-specific ENVs such as RAILS_ENV.

- name: precompile assets with asdf in $PATH and $RAILS_ENV set to production
  command: "rails assets:precompile"
  args:
    chdir: /opt/my_app
  environment:
    PATH: "/opt/asdf/bin:/opt/asdf/shims:{{ ansible_env.PATH }}"
    RAILS_ENV: production

How to run command multiple times in a loop

Use the loop keyword to run command multiple times in a loop.

- name: run commands with asdf in $PATH and $RAILS_ENV set to production
  command: "{{ item }}"
  args:
    chdir: /opt/my_app
  environment:
    PATH: "/opt/asdf/bin:/opt/asdf/shims:{{ ansible_env.PATH }}"
    RAILS_ENV: production
  loop:
    - "rake db:migrate"
    - "rails assets:precompile"

How to capture command module output

Use the register keyword to capture the output of any commands you run.

- name: make a test file with command module
  command: touch /tmp/test_file
  register: command_output

- debug: var=command_output

The debug task above will output the following:

ok: [123.123.123.123] => {
    "touch_output": {
        "changed": true,
        "cmd": [
            "touch",
            "/tmp/test_file"
        ],
        "delta": "0:00:00.003577",
        "end": "2018-12-26 05:45:17.411042",
        "failed": false,
        "rc": 0,
        "start": "2018-12-26 05:45:17.407465",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "",
        "stdout_lines": [],
        "warnings": [...]
    }
}

How to capture command module output from a loop

When using the command module in a loop, the output of each item in the loop will go into the results key of the registered variable.

- name: make multiple test files with command module
  command: "touch /tmp/test_file_{{ item }}"
  register: command_output
  loop:
    - 1
    - 2

- debug: var=command_output
ok: [123.123.123.123] => {
    "command_output": {
        "changed": true,
        "msg": "All items completed",
        "results": [
            {
                ...
                "changed": true,
                "cmd": [
                    "touch",
                    "/tmp/test_file_1"
                ],
                "delta": "0:00:00.003201",
                "end": "2018-12-26 05:51:46.044893",
                "failed": false,
                "invocation": {...},
                "item": "1",
                "rc": 0,
                "start": "2018-12-26 05:51:46.041692",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "",
                "stdout_lines": []
            },
            {
                ...
                "changed": true,
                "cmd": [
                    "touch",
                    "/tmp/test_file_2"
                ],
                "delta": "0:00:00.003118",
                "end": "2018-12-26 05:51:46.360661",
                "failed": false,
                "invocation": {...},
                "item": "2",
                "rc": 0,
                "start": "2018-12-26 05:51:46.357543",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "",
                "stdout_lines": []
            }
        ],
        "warnings": [...]
    }
}

Further reading

Ansible command Module on Ansible Docs

Comment & Share