网络宣传网站建设,电商网站设计思维导图,湖南高端建设网站,河北沙河市规划局或建设局网站环境
管理节点#xff1a;Ubuntu 22.04控制节点#xff1a;CentOS 8Ansible#xff1a;2.15.6
循环的方法
loopwith_lookupuntil
用这几种方式都可以实现循环。其中#xff0c; loop 是推荐的用法#xff0c;在很多时候能够替换 with_lookup 。
loop…环境
管理节点Ubuntu 22.04控制节点CentOS 8Ansible2.15.6
循环的方法
loopwith_lookupuntil
用这几种方式都可以实现循环。其中 loop 是推荐的用法在很多时候能够替换 with_lookup 。
loop 和 with_lookup
with_lookup 使用了lookup插件比如 with_items 使用的是 items lookup。注可参见我另一篇文档。
loop 等同于 with_list 。注意 loop 是作用在list上的如果用在字符串上会报错。
---
- hosts: alltasks:- name: task1debug:msg: {{ item }}loop: {{ [aaa, bbb, ccc] }}- name: task2debug:msg: {{ item }}with_list: {{ [aaa, bbb, ccc] }}- name: task3debug:msg: {{ item }}with_items: {{ [aaa, bbb, ccc] }}运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (itembbb) {msg: bbb
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}TASK [task2] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (itembbb) {msg: bbb
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}TASK [task3] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (itembbb) {msg: bbb
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}可见本例中 loop with_list with_items 的效果是一样的。
但是对于嵌套的list loop 和 with_items 并不是完全等同的。
......- name: task4debug:msg: {{ item }}loop: {{ [aaa, [bbb, [ddd, eee]], ccc] }}- name: task5debug:msg: {{ item }}with_items: {{ [aaa, [bbb, [ddd, eee]], ccc] }}
......运行结果如下
TASK [task4] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (item[bbb, [ddd, eee]]) {msg: [bbb,[ddd,eee]]
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}TASK [task5] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (itembbb) {msg: bbb
}
ok: [192.168.1.55] (item[ddd, eee]) {msg: [ddd,eee]
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}可见
loop 只针对最外层的list不管是否有嵌套。with_items 则是解开了第一层嵌套的list。这个行为比较诡异要么就不要管嵌套要么就全部处理为什么只处理第一层嵌套呢
实际上对于 loop 可用 flatten filter来指定解开嵌套
注flatten是扁平化的意思这里的扁平化和Java8里扁平化流的概念类似即把层次结构转换为线性结构
......- name: task6debug:msg: {{ item }}loop: {{ [aaa, [bbb, [ddd, eee]], ccc] | flatten }}- name: task7debug:msg: {{ item }}loop: {{ [aaa, [bbb, [ddd, eee]], ccc] | flatten(levels1) }}
......运行结果如下
TASK [task6] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (itembbb) {msg: bbb
}
ok: [192.168.1.55] (itemddd) {msg: ddd
}
ok: [192.168.1.55] (itemeee) {msg: eee
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}TASK [task7] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (itembbb) {msg: bbb
}
ok: [192.168.1.55] (item[ddd, eee]) {msg: [ddd,eee]
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}可见 flatten 默认会处理所有嵌套也可以通过 levels 选项指定处理几层嵌套。
由于 with_items 处理一层嵌套所以 with_items 就相当于 loop 指定了 flatten(levels1) 。在本例中task5和task7的运行结果是一样的。
需要使用 lookup 的循环多使用 with_lookup 语句而不是 loop 语句。比如
---
- hosts: alltasks:- name: task1debug:msg: {{ item }}loop: {{ lookup(fileglob, /tmp/*.txt, wantlistTrue) }}- name: task2debug:msg: {{ item }}with_fileglob: /tmp/*.txt运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item/tmp/b.txt) {msg: /tmp/b.txt
}
ok: [192.168.1.55] (item/tmp/a.txt) {msg: /tmp/a.txt
}TASK [task2] ***************************************************************************************
ok: [192.168.1.55] (item/tmp/b.txt) {msg: /tmp/b.txt
}
ok: [192.168.1.55] (item/tmp/a.txt) {msg: /tmp/a.txt
}显然此处使用 with_fileglob 比使用 loop 要简洁。
注 fileglob 获取指定目录下符合条件的文件名不包含子目录。
循环的种类
简单list
---
- hosts: allvars:var1: [aaa, bbb, ccc]tasks:- name: task1 # list常量debug:msg: {{ item }}loop: {{ [aaa, bbb, ccc] }}# loop: [aaa, bbb, ccc] 可以简写- name: task2 # list常量debug:msg: {{ item }}loop:- aaa # 引号可以省略- bbb- ccc- name: task3 # list变量debug:msg: {{ item }}loop: {{ var1 }}运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (itembbb) {msg: bbb
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}TASK [task2] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (itembbb) {msg: bbb
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}TASK [task3] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: aaa
}
ok: [192.168.1.55] (itembbb) {msg: bbb
}
ok: [192.168.1.55] (itemccc) {msg: ccc
}复杂list
---
- hosts: allvars:var1: [{name: Tom, age: 20}, {name: Jerry, age: 18}]tasks:- name: task1debug:msg: Name: {{ item.name }}. Age: {{ item.age }}loop: {{ [{ name: Tom, age: 20 }, { name: Jerry, age: 18 }] }}#loop: {{ [{ name: Tom, age: 20 }, { name: Jerry, age: 18 }] }} # 报错说name未定义#loop: [{ name: Tom, age: 20 }, { name: Jerry, age: 18 }] # OK#loop: [{ name: Tom, age: 20 }, { name: Jerry, age: 18 }] # OK- name: task2debug:msg: Name: {{ item.name }}. Age: {{ item.age }}loop:- { name: Tom, age: 20 }- { name: Jerry, age: 18 }- name: task3debug:msg: Name: {{ item.name }}. Age: {{ item.age }}loop: {{ var1 }}可以看到对于key要不要加引号行为好像有点诡异最好还是加上吧。
运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item{name: Tom, age: 20}) {msg: Name: Tom. Age: 20
}
ok: [192.168.1.55] (item{name: Jerry, age: 18}) {msg: Name: Jerry. Age: 18
}TASK [task2] ***************************************************************************************
ok: [192.168.1.55] (item{name: Tom, age: 20}) {msg: Name: Tom. Age: 20
}
ok: [192.168.1.55] (item{name: Jerry, age: 18}) {msg: Name: Jerry. Age: 18
}TASK [task3] ***************************************************************************************
ok: [192.168.1.55] (item{name: Tom, age: 20}) {msg: Name: Tom. Age: 20
}
ok: [192.168.1.55] (item{name: Jerry, age: 18}) {msg: Name: Jerry. Age: 18
}dict
如果要遍历一个dict则需要使用 dict2items filter将其转换为list
---
- hosts: allvars:var1: {name: Tom, age: 20}tasks:- name: task1debug:msg: Key: {{ item.key }}. Value: {{ item.value }}loop: {{ {name: Tom, age: 20} | dict2items }}- name: task2debug:msg: Key: {{ item.key }}. Value: {{ item.value }}loop: {{ var1 | dict2items }}运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item{key: name, value: Tom}) {msg: Key: name. Value: Tom
}
ok: [192.168.1.55] (item{key: age, value: 20}) {msg: Key: age. Value: 20
}TASK [task2] ***************************************************************************************
ok: [192.168.1.55] (item{key: name, value: Tom}) {msg: Key: name. Value: Tom
}
ok: [192.168.1.55] (item{key: age, value: 20}) {msg: Key: age. Value: 20
}本例中dict为
{name: Tom, age: 20}转为list后 [{key: name,value: Tom},{key: age,value: 20}]循环结果的register变量
---
- hosts: alltasks:- name: task1shell: echo {{ item }}loop: {{ [aaa, bbb] }}register: var1- name: task2debug:msg: {{ var1 }}运行结果如下
TASK [task1] ***************************************************************************************
changed: [192.168.1.55] (itemaaa)
changed: [192.168.1.55] (itembbb)TASK [task2] ***************************************************************************************
ok: [192.168.1.55] {msg: {changed: true,msg: All items completed,results: [{ansible_loop_var: item,changed: true,cmd: echo aaa,delta: 0:00:00.002332,end: 2023-11-21 22:29:54.990234,failed: false,invocation: {module_args: {_raw_params: echo aaa,_uses_shell: true,argv: null,chdir: null,creates: null,executable: null,removes: null,stdin: null,stdin_add_newline: true,strip_empty_ends: true}},item: aaa,msg: ,rc: 0,start: 2023-11-21 22:29:54.987902,stderr: ,stderr_lines: [],stdout: aaa,stdout_lines: [aaa]},{ansible_loop_var: item,changed: true,cmd: echo bbb,delta: 0:00:00.002036,end: 2023-11-21 22:29:55.223227,failed: false,invocation: {module_args: {_raw_params: echo bbb,_uses_shell: true,argv: null,chdir: null,creates: null,executable: null,removes: null,stdin: null,stdin_add_newline: true,strip_empty_ends: true}},item: bbb,msg: ,rc: 0,start: 2023-11-21 22:29:55.221191,stderr: ,stderr_lines: [],stdout: bbb,stdout_lines: [bbb]}],skipped: false}
}可见register变量把循环操作的结果放到了叫做 results 的list里。因此后续可以遍历 results 做相应处理比如
---
- hosts: alltasks:- name: task1shell: cat {{ item }}loop: {{ [/tmp/a.txt, /tmp/d.txt] }}register: var1ignore_errors: true- name: task2debug:msg: {{ var1 }}- name: task3fail:msg: Something is wrong!when: item.rc ! 0loop: {{ var1.results }}假设 /tmp/d.txt 不存在则运行结果如下
TASK [task1] ***************************************************************************************
changed: [192.168.1.55] (item/tmp/a.txt)
failed: [192.168.1.55] (item/tmp/d.txt) {ansible_loop_var: item, changed: true, cmd: cat /tmp/d.txt, delta: 0:00:00.002438, end: 2023-11-21 22:46:28.216904, item: /tmp/d.txt, msg: non-zero return code, rc: 1, start: 2023-11-21 22:46:28.214466, stderr: cat: /tmp/d.txt: No such file or directory, stderr_lines: [cat: /tmp/d.txt: No such file or directory], stdout: , stdout_lines: []}
...ignoringTASK [task2] ***************************************************************************************
ok: [192.168.1.55] {msg: {changed: true,failed: true,msg: One or more items failed,results: [{ansible_loop_var: item,changed: true,cmd: cat /tmp/a.txt,delta: 0:00:00.003006,end: 2023-11-21 22:46:27.995302,failed: false,invocation: {module_args: {_raw_params: cat /tmp/a.txt,_uses_shell: true,argv: null,chdir: null,creates: null,executable: null,removes: null,stdin: null,stdin_add_newline: true,strip_empty_ends: true}},item: /tmp/a.txt,msg: ,rc: 0,start: 2023-11-21 22:46:27.992296,stderr: ,stderr_lines: [],stdout: aaaaa\nb\nccccc,stdout_lines: [aaaaa,b,ccccc]},{ansible_loop_var: item,changed: true,cmd: cat /tmp/d.txt,delta: 0:00:00.002438,end: 2023-11-21 22:46:28.216904,failed: true,invocation: {module_args: {_raw_params: cat /tmp/d.txt,_uses_shell: true,argv: null,chdir: null,creates: null,executable: null,removes: null,stdin: null,stdin_add_newline: true,strip_empty_ends: true}},item: /tmp/d.txt,msg: non-zero return code,rc: 1,start: 2023-11-21 22:46:28.214466,stderr: cat: /tmp/d.txt: No such file or directory,stderr_lines: [cat: /tmp/d.txt: No such file or directory],stdout: ,stdout_lines: []}],skipped: false}
}TASK [task3] ***************************************************************************************
skipping: [192.168.1.55] (item{changed: True, stdout: aaaaa\nb\nccccc, stderr: , rc: 0, cmd: cat /tmp/a.txt, start: 2023-11-21 22:46:27.992296, end: 2023-11-21 22:46:27.995302, delta: 0:00:00.003006, msg: , invocation: {module_args: {_raw_params: cat /tmp/a.txt, _uses_shell: True, stdin_add_newline: True, strip_empty_ends: True, argv: None, chdir: None, executable: None, creates: None, removes: None, stdin: None}}, stdout_lines: [aaaaa, b, ccccc], stderr_lines: [], failed: False, item: /tmp/a.txt, ansible_loop_var: item})
failed: [192.168.1.55] (item{changed: True, stdout: , stderr: cat: /tmp/d.txt: No such file or directory, rc: 1, cmd: cat /tmp/d.txt, start: 2023-11-21 22:46:28.214466, end: 2023-11-21 22:46:28.216904, delta: 0:00:00.002438, failed: True, msg: non-zero return code, invocation: {module_args: {_raw_params: cat /tmp/d.txt, _uses_shell: True, stdin_add_newline: True, strip_empty_ends: True, argv: None, chdir: None, executable: None, creates: None, removes: None, stdin: None}}, stdout_lines: [], stderr_lines: [cat: /tmp/d.txt: No such file or directory], item: /tmp/d.txt, ansible_loop_var: item}) {ansible_loop_var: item, changed: false, item: {ansible_loop_var: item, changed: true, cmd: cat /tmp/d.txt, delta: 0:00:00.002438, end: 2023-11-21 22:46:28.216904, failed: true, invocation: {module_args: {_raw_params: cat /tmp/d.txt, _uses_shell: true, argv: null, chdir: null, creates: null, executable: null, removes: null, stdin: null, stdin_add_newline: true, strip_empty_ends: true}}, item: /tmp/d.txt, msg: non-zero return code, rc: 1, start: 2023-11-21 22:46:28.214466, stderr: cat: /tmp/d.txt: No such file or directory, stderr_lines: [cat: /tmp/d.txt: No such file or directory], stdout: , stdout_lines: []}, msg: Something is wrong!}本例中由于 /tmp/d.txt 不存在 results 的第2个元素其rc值为1。
注意每一次迭代其结果就会放到register变量里而不是整个循环结束后才放的。
---
- hosts: alltasks:- name: task1shell: echo {{ item }}loop:- aaa- bbbregister: var1changed_when: var1.stdout ! aaa运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (itemaaa)
changed: [192.168.1.55] (itembbb)可见第一次迭代没有满足判断条件而第二次迭代满足判断条件了。
复杂循环
遍历嵌套list
---
- hosts: alltasks:- name: task1debug:msg: {{ item[0] }} {{ item[1] }}loop: {{ [Zhang, Li] | product([San, Si]) | list }}运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item[Zhang, San]) {msg: Zhang San
}
ok: [192.168.1.55] (item[Zhang, Si]) {msg: Zhang Si
}
ok: [192.168.1.55] (item[Li, San]) {msg: Li San
}
ok: [192.168.1.55] (item[Li, Si]) {msg: Li Si
}本例中把两个list做笛卡尔乘积生成了一个新的嵌套list [[Zhang,San],[Zhang,Si],[Li,San],[Li,Si]]然后遍历外层list并通过 item[0] 、 item[1] 访问内层list的元素。
Retry
---
- hosts: alltasks:- name: task1shell: cat /tmp/a.txtregister: var1until: var1.stdout.find(OK) ! -1retries: 3delay: 5运行结果如下
TASK [task1] ***************************************************************************************
FAILED - RETRYING: [192.168.1.55]: task1 (3 retries left).
FAILED - RETRYING: [192.168.1.55]: task1 (2 retries left).
FAILED - RETRYING: [192.168.1.55]: task1 (1 retries left).
fatal: [192.168.1.55]: FAILED! {attempts: 3, changed: true, cmd: cat /tmp/a.txt, delta: 0:00:00.002228, end: 2023-11-23 07:53:18.333193, msg: , rc: 0, start: 2023-11-23 07:53:18.330965, stderr: , stderr_lines: [], stdout: aaaaa\nb\nccccc, stdout_lines: [aaaaa, b, ccccc]}在运行过程中编辑 /tmp/a.txt 文件注意是在目标机器上添加 OK 的内容则运行结果如下
TASK [task1] ***************************************************************************************
FAILED - RETRYING: [192.168.1.55]: task1 (3 retries left).
FAILED - RETRYING: [192.168.1.55]: task1 (2 retries left).
changed: [192.168.1.55]注
retries 的缺省值是 3 delay 的缺省值是 5 。
遍历inventory
假设 /etc/ansible/hosts 内容如下
[myvms]
192.168.1.55[myself]
127.0.0.1---
- hosts: alltasks:- name: task1debug:msg: {{ item }}loop: {{ groups[all] }}#loop: {{ groups[myvms] }}运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item192.168.1.55) {msg: 192.168.1.55
}
ok: [192.168.1.55] (item127.0.0.1) {msg: 127.0.0.1
}
ok: [127.0.0.1] (item192.168.1.55) {msg: 192.168.1.55
}
ok: [127.0.0.1] (item127.0.0.1) {msg: 127.0.0.1
}可见打印了所有的主机名。
为什么打印了两次呢这是因为指定了 hosts: all 所以在两个目标机器上都运行了一次。
若改为 hosts: myvms 则运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item192.168.1.55) {msg: 192.168.1.55
}
ok: [192.168.1.55] (item127.0.0.1) {msg: 127.0.0.1
}如果只想遍历 myvms 则把 loop: {{ groups[all] }} 改为 loop: {{ groups[myvms] }} 运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item192.168.1.55) {msg: 192.168.1.55
}也可以通过 loop: {{ ansible_play_batch }} 指定遍历当前play的主机
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item192.168.1.55) {msg: 192.168.1.55
}注 groups 和 ansible_play_batch 都是Ansible的特殊变量参见 https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html 。
还可以通过 inventory_hostnames lookup来指定遍历的主机
---
- hosts: myvmstasks:- name: task1debug:msg: {{ item }}loop: {{ query(inventory_hostnames, all) }}运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item192.168.1.55) {msg: 192.168.1.55
}
ok: [192.168.1.55] (item127.0.0.1) {msg: 127.0.0.1
}遍历 all 同时排除 myvms 则指定loop: {{ query(inventory_hostnames, all:!myvms) }}
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item127.0.0.1) {msg: 127.0.0.1
}loop_control
label
前面我们提到遍历一个dict
---
- hosts: allvars:var1: {name: Tom, age: 20}tasks:- name: task1debug:msg: Key: {{ item.key }}. Value: {{ item.value }}loop: {{ {name: Tom, age: 20} | dict2items }}#loop_control:# label: {{ item.key}}运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item{key: name, value: Tom}) {msg: Key: name. Value: Tom
}
ok: [192.168.1.55] (item{key: age, value: 20}) {msg: Key: age. Value: 20
}注意其中的 (item{key: name, value: Tom}) 等如果item数据量很大则输出量很大。此处可以使用 label 指定打印的内容比如只打印key不打印value见注释部分。
运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (itemname) {msg: Key: name. Value: Tom
}
ok: [192.168.1.55] (itemage) {msg: Key: age. Value: 20
}pause
在每次循环迭代之间暂停一段时间秒。
---
- hosts: alltasks:- name: task1debug:msg: {{ item }}loop: {{ [aaa, bbb, ccc] }}loop_control:pause: 3index_var
指定下标变量然后通过该变量获取下标值从0开始。
---
- hosts: alltasks:- name: task1debug:msg: {{ idx }}: {{ item }}loop: {{ [aaa, bbb, ccc] }}loop_control:index_var: idx运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: 0: aaa
}
ok: [192.168.1.55] (itembbb) {msg: 1: bbb
}
ok: [192.168.1.55] (itemccc) {msg: 2: ccc
}loop_var
循环的元素名称默认叫做 item 而对于嵌套循环为避免混淆内外循环的item可用 loop_var 指定item名称。
创建文件 test19.yml 如下
---
- hosts: alltasks:- name: task1include_tasks: test20.ymlloop: [1, 2, 3]loop_control:loop_var: item_outer创建文件 test20.yml 如下
---
- name: inner_task1debug:msg: Outer item {{ item_outer }}, Inner item {{ item_inner }}loop: {{ [aaa, bbb, ccc] }}loop_control:loop_var: item_inner运行结果如下
TASK [task1] ***************************************************************************************
included: /root/temp/temp1121/test20.yml for 192.168.1.55 (item1)
included: /root/temp/temp1121/test20.yml for 192.168.1.55 (item2)
included: /root/temp/temp1121/test20.yml for 192.168.1.55 (item3)TASK [inner_task1] *********************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: Outer item 1, Inner item aaa
}
ok: [192.168.1.55] (itembbb) {msg: Outer item 1, Inner item bbb
}
ok: [192.168.1.55] (itemccc) {msg: Outer item 1, Inner item ccc
}TASK [inner_task1] *********************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: Outer item 2, Inner item aaa
}
ok: [192.168.1.55] (itembbb) {msg: Outer item 2, Inner item bbb
}
ok: [192.168.1.55] (itemccc) {msg: Outer item 2, Inner item ccc
}TASK [inner_task1] *********************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: Outer item 3, Inner item aaa
}
ok: [192.168.1.55] (itembbb) {msg: Outer item 3, Inner item bbb
}
ok: [192.168.1.55] (itemccc) {msg: Outer item 3, Inner item ccc
}本例中外部循环的item命名为 item_outer 而内部循环的item命名为 item_inner 。
扩展循环变量
添加 extended: true 则可以访问如下变量
ansible_loop.allitems 所有元素ansible_loop.index 从1开始ansible_loop.index0 从0开始ansible_loop.revindex 倒数从1开始ansible_loop.revindex0 倒数从0开始ansible_loop.first 是否是第一个元素ansible_loop.last 是否是最后一个元素ansible_loop.length 元素数量ansible_loop.previtem 前一个元素第一次迭代时未定义ansible_loop.nextitem 后一个元素最后一次迭代时未定义
---
- hosts: alltasks:- name: task1debug:msg: ansible_loop.allitems {{ ansible_loop.allitems }}, ansible_loop.index {{ ansible_loop.index }}, ansible_loop.index0 {{ ansible_loop.index0 }}, ansible_loop.revindex {{ ansible_loop.revindex }}, ansible_loop.revindex0 {{ ansible_loop.revindex0 }}, ansible_loop.first {{ ansible_loop.first }}, ansible_loop.last {{ ansible_loop.last }}, ansible_loop.length {{ ansible_loop.length }}, ansible_loop.previtem {{ ansible_loop.previtem | default(no previous) }}, ansible_loop.nextitem {{ ansible_loop.nextitem | default(no next) }}loop: {{ [aaa, bbb, ccc] }}loop_control:extended: true运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (itemaaa) {msg: ansible_loop.allitems [aaa, bbb, ccc], ansible_loop.index 1, ansible_loop.index0 0, ansible_loop.revindex 3, ansible_loop.revindex0 2, ansible_loop.first True, ansible_loop.last False, ansible_loop.length 3, ansible_loop.previtem no previous, ansible_loop.nextitem bbb
}
ok: [192.168.1.55] (itembbb) {msg: ansible_loop.allitems [aaa, bbb, ccc], ansible_loop.index 2, ansible_loop.index0 1, ansible_loop.revindex 2, ansible_loop.revindex0 1, ansible_loop.first False, ansible_loop.last False, ansible_loop.length 3, ansible_loop.previtem aaa, ansible_loop.nextitem ccc
}
ok: [192.168.1.55] (itemccc) {msg: ansible_loop.allitems [aaa, bbb, ccc], ansible_loop.index 3, ansible_loop.index0 2, ansible_loop.revindex 1, ansible_loop.revindex0 0, ansible_loop.first False, ansible_loop.last True, ansible_loop.length 3, ansible_loop.previtem bbb, ansible_loop.nextitem no next
}注如果 ansible_loop.allitems 很大为了节省内存可以设置 extended_allitems: false
loop_control:extended: trueextended_allitems: false获取 loop_var 的值
比如指定了 loop_var: myitem 则可以通过 {{ myitem }} 来获取item也可以通过 {{ lookup(vars, ansible_loop_var) }} 获取item。
---
- hosts: alltasks:- name: task1debug:msg: {{ myitem }} , {{ lookup(vars, ansible_loop_var) }}loop: [1, 2, 3]loop_control:loop_var: myitem运行结果如下
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] (item1) {msg: 1 , 1
}
ok: [192.168.1.55] (item2) {msg: 2 , 2
}
ok: [192.168.1.55] (item3) {msg: 3 , 3
}可见二者效果是一样的。
参考
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.htmlhttps://docs.ansible.com/ansible/latest/reference_appendices/special_variables.htmlhttps://docs.ansible.com/ansible/latest/inventory_guide/intro_patterns.html