I have two variables:
name: "abc232323defg10"
cycle: "4"
I need to generate a list:
list:
- abc232323defg10
- abc232323defg9
- abc232323defg8
- abc232323defg7
where:
abc232323defg9 = abc232323defg(10-(cycle-3)),
abc232323defg8 = abc232323defg(10-(cycle-2)),
abc232323defg7 = abc232323defg(10-(cycle-1))
The variable "cycle" is the same as the number of items in the list, and I already have item where last 2 characters are the "largest number" (that is number 10 in the example). So other items should have last two characters subtracted from this "largest number" (with increments for each cycle). Cycle is never bigger then "largest number", but can be equal. Order in the list is not relevant.
PS last two characters can be any number or even combination of one letter (a-z,A-Z) and one number. So it can be t1, or e9, or 88... that is why I think I need regex.
Any idea?
CodePudding user response:
An example playbook with
---
- hosts: localhost
become: false
gather_facts: false
vars:
NAME: "ABCD1000"
COUNTER: 4
tasks:
- name: Example loop
debug:
msg: "{{ NAME | regex_search('[0-9] ') | int - item | int }}"
loop: "{{ range(1, COUNTER 1) }}"
will result into an output of
TASK [Example loop] **********
ok: [localhost] => (item=1) =>
msg: '999'
ok: [localhost] => (item=2) =>
msg: '998'
ok: [localhost] => (item=3) =>
msg: '997'
ok: [localhost] => (item=4) =>
msg: '996'
The filter
NAME | regex_search('[0-9] ') | int
will just extract the digits from the name and cast it to integer for further processing.
The part
- item | int
will subtract the loop counter from the gathered integer value.
Then you just need to adjust the start and end values, as well the order if necessary.
Further Q&A and Documenation
- Extract digits from string with Ansible
- Get Number from hostname in Ansible
- Running an Ansible loop in reverse
- Extended loop counters
- Forcing the data type
In respect to your comments and update and to catch up the last numeric character from your input value, you may test with
- name: Last numeric characters
debug:
msg: "{{ NAME | regex_search('(\\d )(?!.*\\d)') }}"
resulting for example input values of abcd123t1
, abc123e9
, or abc12378
into an output of 1
, 9
or 12378
.
Similar Q&A
You may also consider to have a look how big your input values are since the loop
TASK [Last numeric character] **********
ok: [localhost] =>
msg: '1'
TASK [Example loop] **********
ok: [localhost] => (item=1) =>
msg: '0'
ok: [localhost] => (item=2) =>
msg: '-1'
ok: [localhost] => (item=3) =>
msg: '-2'
ok: [localhost] => (item=4) =>
msg: '-3'
could end up with negative values.
CodePudding user response:
Given the variables
_name: "abc232323defg10"
cycle: "4"
Declare the variables prefix and index by splitting _name
prefix: "{{ _name|regex_replace('^(. ?)(\\d )$', '\\1') }}"
index: "{{ _name|regex_replace('^(. ?)(\\d )$', '\\2') }}"
give
prefix: abc232323defg
index: 10
Declare the list indexes
indexes: "{{ query('sequence', params) }}"
params: "start={{ index|int }} end={{ index|int - cycle|int 1 }} stride=-1"
give
indexes: ['10', '9', '8', '7']
Finally, create product of the prefix and indexes, and join them
names: "{{ [prefix]|product(indexes)|map('join')|list }}"
gives the expected result
names:
- abc232323defg10
- abc232323defg9
- abc232323defg8
- abc232323defg7
Example of a complete playbook for testing
- hosts: localhost
vars:
_name: "abc232323defg10"
cycle: "4"
prefix: "{{ _name|regex_replace('^(. ?)(\\d )$', '\\1') }}"
index: "{{ _name|regex_replace('^(. ?)(\\d )$', '\\2') }}"
indexes: "{{ query('sequence', params) }}"
params: "start={{ index|int }} end={{ index|int - cycle|int 1 }} stride=-1"
names: "{{ [prefix]|product(indexes)|map('join')|list }}"
tasks:
- debug:
msg: |
prefix: {{ prefix }}
index: {{ index }}
indexes: {{ indexes }}
names:
{{ names|to_nice_yaml|indent(2) }}