arcolife arcolife - 4 months ago 35
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[@]}"
2


this seems to be an issue as I have tried all quoting combinations. I've opened an issue here, just in case: https://github.com/ansible/ansible/issues/16968

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

$ a="aaa"; echo "${#a}"
3
$ 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}"


UPDATE:

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

@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

Answer

{# 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
ansible 2.1.1.0
$cat xx.yml
---
- hosts: localhost
  connection: local
  tasks:
    - 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"
}
Comments