Safer Commands with argv in Ansible: Pros, Cons, and Real Examples
When using Ansible to automate tasks, the command module is your bread and butter for executing system commands. But did you know that there’s a safer, cleaner, and more predictable way to pass arguments? Meet argvāan alternative to writing commands as strings.
In this post, Iāll explore the pros and cons of using argv, and Iāll walk through several real-world examples tailored to web servers and mail servers.
Why Use argv Instead of a Command String?
ā Pros
- Avoids Shell Parsing Issues: Each argument is passed exactly as intended, with no surprises from quoting or spaces.
- More Secure: No shell = no risk of shell injection.
- Clearer Syntax: Every argument is explicitly defined, improving readability.
- Predictable: Behavior is consistent across different platforms and setups.
ā Cons
- No Shell Features: You can’t use pipes (
|), redirection (>), or environment variables like$HOME. - More Verbose: Every argument must be a separate list item. Itās explicit, but more to type.
- Not for Shell Built-ins: Commands like
cd,export, orechowith redirection won’t work.
Real-World Examples
Letās apply this to actual use cases.
š§ Restarting Nginx with argv
- name: Restart Nginx using argv
hosts: amedee.be
become: yes
tasks:
- name: Restart Nginx
ansible.builtin.command:
argv:
- systemctl
- restart
- nginx
š¬ Check Mail Queue on a Mail-in-a-Box Server
- name: Check Postfix mail queue using argv
hosts: box.vangasse.eu
become: yes
tasks:
- name: Get mail queue status
ansible.builtin.command:
argv:
- mailq
register: mail_queue
- name: Show queue
ansible.builtin.debug:
msg: "{{ mail_queue.stdout_lines }}"
šļø Back Up WordPress Database
- name: Backup WordPress database using argv
hosts: amedee.be
become: yes
vars:
db_user: wordpress_user
db_password: wordpress_password
db_name: wordpress_db
tasks:
- name: Dump database
ansible.builtin.command:
argv:
- mysqldump
- -u
- "{{ db_user }}"
- -p{{ db_password }}
- "{{ db_name }}"
- --result-file=/root/wordpress_backup.sql
ā ļø Avoid exposing credentials directlyāuse Ansible Vault instead.
Using argv with Interpolation
Ansible lets you use Jinja2-style variables ({{ }}) inside argv items.
š Restart a Dynamic Service
- name: Restart a service using argv and variable
hosts: localhost
become: yes
vars:
service_name: nginx
tasks:
- name: Restart
ansible.builtin.command:
argv:
- systemctl
- restart
- "{{ service_name }}"
š Timestamped Backups
- name: Timestamped DB backup
hosts: localhost
become: yes
vars:
db_user: wordpress_user
db_password: wordpress_password
db_name: wordpress_db
tasks:
- name: Dump with timestamp
ansible.builtin.command:
argv:
- mysqldump
- -u
- "{{ db_user }}"
- -p{{ db_password }}
- "{{ db_name }}"
- --result-file=/root/wordpress_backup_{{ ansible_date_time.iso8601 }}.sql
š§© Dynamic Argument Lists
Avoid join(' '), which collapses the list into a single string.
ā Wrong:
argv:
- ls
- "{{ args_list | join(' ') }}" # BAD: becomes one long string
ā Correct:
argv: ["ls"] + args_list
Or if the length is known:
argv:
- ls
- "{{ args_list[0] }}"
- "{{ args_list[1] }}"
š£ Interpolation Inside Strings
- name: Greet with hostname
hosts: localhost
tasks:
- name: Print message
ansible.builtin.command:
argv:
- echo
- "Hello, {{ ansible_facts['hostname'] }}!"
When to Use argv
ā
Commands with complex quoting or multiple arguments
ā
Tasks requiring safety and predictability
ā
Scripts or binaries that take arguments, but not full shell expressions
When to Avoid argv
ā When you need pipes, redirection, or shell expansion
ā When you’re calling shell built-ins
Final Thoughts
Using argv in Ansible may feel a bit verbose, but it offers precision and security that traditional string commands lack. When you need reliable, cross-platform automation that avoids the quirks of shell parsing, argv is the better choice.
Prefer safety? Choose argv.
Need shell magic? Use the shell module.
Have a favorite argv trick or horror story? Drop it in the comments below.

