arcolife arcolife - 11 months ago 112
Linux Question

bash array element count operation in ansible

Wondering how this might work in ansible task?

- shell: |
y=(aa bb); echo "${#y[@]}"
register: r

Currently it gives the following error

ERROR: There was an error while parsing the task 'shell y=(aa bb); echo "${#y[@]}"\n'.
Make sure quotes are matched or escaped properly

..that's because of the character '#'. I can't escape it because otherwise that's an invalid bash operation. If I escape it, I get:

$ ansible -c localhost -m shell -a 'y=(aa bb); echo "${\#y[@]}"' -i hosts.ini test-host

localhost | FAILED | rc=1 >>
/bin/sh: ${\#y[@]}: bad substitution

The current equivalent result of this op on a linux cmdline is:

$ y=(aa bb); echo "${#y[@]}"

this seems to be an issue as I have tried all quoting combinations. I've opened an issue here, just in case:

A similar easier example that runs in bash, but not in ansible is:

$ a="aaa"; echo "${#a}"
$ ansible -c localhost -m shell -a 'a="aaa"; echo "${#a}"' -i hosts.ini test-host

ERROR! failed at splitting arguments, either an unbalanced jinja2 block or quotes: a="aaa"; echo "${#a}"


As described in the github issue hyperlinked in the question, the version I wanna use this with, is

@konstantin-suvorov's answer below works with ansible 2.1+ following jinja templating's comment system. In case you're wondering how to get around this problem of getting length of the array with older ansible versions, this one-liner might help:

y=(aa bb cc); g=("${!y[@]}"); res=`expr ${g[-1]} + 1`; echo $res

The workaround is to first get the indices of all elements using
instead of getting count with
. Apparently
gives no problem


{# is a comment sequence in jinja, so you variable ends up with unbalanced comment block.

You can workaround this by templating { before #:

- shell: |
         y=(aa bb cc); echo "${{"{"}}#y[@]}"

Update: full example:

$ansible --version
$cat xx.yml
- hosts: localhost
  connection: local
    - shell: |
             y=(aa bb cc); echo "${{"{"}}#y[@]}"
      register: result
    - debug: var=result.stdout
$ansible-playbook xx.yml
PLAY [localhost] ***************************************************************
TASK [command] *****************************************************************
changed: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
    "result.stdout": "3"