When working with Ansible playbooks, many engineers encounter a common limitation: the --limit
or -l
flag doesn't behave as expected when specifying multiple hosts directly in the command line. The standard approach:
ansible-playbook -i inventory.ini -l host1.com host2.com playbook.yml
Results in the frustrating error:
ERROR! the playbook: host2.com could not be found
The fundamental issue lies in how command-line arguments are parsed. Ansible interprets everything after -l
as part of the limit pattern until it encounters another flag. To properly specify multiple hosts, you need to:
- Quote the entire host pattern
- Use proper pattern separators
Solution 1: Comma-separated list
ansible-playbook -i inventory.ini -l "host1.com,host2.com" playbook.yml
Solution 2: Colon-separated list
ansible-playbook -i inventory.ini -l "host1.com:host2.com" playbook.yml
Solution 3: Using wildcard patterns
ansible-playbook -i inventory.ini -l "*.com" playbook.yml
For more complex scenarios, you can combine pattern operators:
# All hosts in datacenter1 except db servers
ansible-playbook -i inventory.ini -l "datacenter1.*:!datacenter1.db*" playbook.yml
For cases where pattern matching isn't sufficient, consider these approaches:
Using temporary inventory files:
echo "host1.com\nhost2.com" > /tmp/hosts && \
ansible-playbook -i inventory.ini -l @/tmp/hosts playbook.yml && \
rm /tmp/hosts
JSON input via stdin:
echo '["host1.com","host2.com"]' | ansible-playbook -i inventory.ini -l @/dev/stdin playbook.yml
- Forgetting to quote patterns with spaces
- Mixing different pattern separators inconsistently
- Not escaping special characters in hostnames
- Assuming host patterns work the same way across all Ansible versions
Here's how we might deploy to multiple web servers while skipping maintenance hosts:
ansible-playbook -i production.ini \
-l "web*.example.com:!web[09].example.com" \
--extra-vars "deploy_version=1.4.2" \
deploy.yml
This command would target all web servers except web0 and web9, passing along the deployment version as a variable.
Pattern matching behavior has evolved across Ansible versions:
- 2.4+: Added support for
@
prefix for inventory files - 2.9+: Improved pattern parsing for IPv6 addresses
- Recent versions: Better error messages for invalid patterns
When working with Ansible in constrained environments, we often encounter situations where modifying inventory files isn't an option. The --limit
(or -l
) flag becomes crucial for targeting specific hosts, but its syntax for multiple hosts isn't immediately obvious from the documentation.
The proper syntax for limiting to multiple hosts inline requires using commas to separate hostnames:
ansible-playbook -i inventory.ini -l "server1.example.com,server2.example.com" playbook.yml
Alternatively, you can use patterns:
ansible-playbook -i inventory.ini -l "server[1:2].example.com" playbook.yml
The original error occurs because Ansible interprets space-separated arguments after -l
as different parameters. Some key observations:
- Always quote the host list when using commas
- The @file syntax works but requires maintaining external files
- Pattern matching can often replace explicit listing
For complex environments, you can combine patterns with logical operators:
ansible-playbook -i inventory.ini -l "server*.example.com:!server-backup.example.com" playbook.yml
This would target all servers except the backup server.
While --limit
is convenient, be aware that:
- Ansible still parses the entire inventory
- Connection overhead remains for all matched hosts
- For very large inventories, explicit host listing may be faster than patterns
Here's a complete command targeting specific web servers for a rolling update:
ansible-playbook -i production.ini \
-l "web-[01:05].prod.example.com" \
--extra-vars "maintenance_mode=true" \
rolling-update.yml