我有一些正在解析的Windows系统(使用winrm)上的文本文件的输出。我试图使剧本失败,如果它没有看到单词"测试"超过一次。
如果playbook至少出现一次"test"这个词,我的脚本就会继续执行:
- name: "Windows Output | Parse file"
win_shell: |
(Get-Content C:TESToutput.txt)
register: 'testing_parse'
- name: "File output | verification"
assert:
that:
- "'test' in testing_parse.stdout"
fail_msg: "Exiting now."
success_msg: "Proceeding with task."
我认为下面的代码可以工作,但它没有:
- name: "File output | verification"
assert:
that:
- "'test' in testing_parse.stdout >= '2'"
fail_msg: "Exiting now."
success_msg: "Proceeding with task."
我如何修复我的assert
任务,使其满足我的要求?
TL;DR
- name: "File output | verification"
vars:
watch_regex: '(?:^|W)(test)(?:$|W)'
assert:
that:
- testing_parse.stdout | regex_findall(watch_regex) | length > 1
fail_msg: "Exiting now."
success_msg: "Proceeding with task."
为什么in
测试不合适
in
返回布尔值
让我们首先看看在几种情况下in
测试得到的结果
$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}"
-e "my_test='a test'"
localhost | SUCCESS => {
"msg": true
}
$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}"
-e "my_test='a test and an other test'"
localhost | SUCCESS => {
"msg": true
}
$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}"
-e "my_test='no word we look for'"
localhost | SUCCESS => {
"msg": false
}
正如你所看到的,它将始终返回一个布尔值,这取决于在干草堆中是否存在指针。
in
找不到单词
还请注意,in
不是很擅长查找单词(因为你提到了这一点),如下所示:
# It will match a substring in a middle of an other word
$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}"
-e my_test="blahtesttoto"
localhost | SUCCESS => {
"msg": true
}
# It will not match a word inside an element of a list...
$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}"
-e '{"my_test":["this is", "a test"]}'
localhost | SUCCESS => {
"msg": false
}
# ... but only an exact match of an element of a list
$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}"
-e '{"my_test":["a", "test"]}'
localhost | SUCCESS => {
"msg": true
}
无论如何你的表达是错误的
最后,让我们来看看你写这个表达式时的尝试:
'test' in testing_parse.stdout >= '2'
这意味着:
- 检查字符串
testing_parse.stdout
是否在词法上优于或等于字符串'2'
。 - 现在检查字符串
'test'
是否在前面的布尔结果中找到。
正如您现在可以通过解释猜测的那样,这绝对不可能返回true
。
regex_findall
救援
查找特定单词的一种方法是使用正则表达式。下面将查找test
单词,即"test"
字符串前面和后面的任何非单词字符(行尾,行首,空白,制表符,标点符号....)。
(?:^|W)(test)(?:$|W)
如果您不熟悉正则表达式,请参阅此答案以获得具体解释,并参阅https://www.regextutorial.org/以获得一般资源(我不是附属的,您可以使用您喜欢的搜索引擎找到其他资源)。
regex_find_all
过滤器可以将一个正则表达式与一个字符串的所有匹配返回到一个列表
$ ansible localhost -m debug
-a "msg={{ my_test | regex_findall('(?:^|\W)(test)(?:$|\W)') }}"
-e "my_test='test'"
localhost | SUCCESS => {
"msg": [
"test"
]
}
$ ansible localhost -m debug
-a "msg={{ my_test | regex_findall('(?:^|\W)(test)(?:$|\W)') }}"
-e "my_test='test and an other test but not blahtesttoto yet test'"
localhost | SUCCESS => {
"msg": [
"test",
"test",
"test"
]
}
$ ansible localhost -m debug
-a "msg={{ my_test | regex_findall('(?:^|\W)(test)(?:$|\W)') }}"
-e "my_test='notest'"
localhost | SUCCESS => {
"msg": []
}
一旦有了这个,我们只需要用length
过滤器计算返回列表中的元素个数。
$ ansible localhost -m debug
-a "msg={{ my_test | regex_findall('(?:^|\W)(test)(?:$|\W)') | length }}"
-e "my_test='test and an other test but not blahtesttoto yet test'"
localhost | SUCCESS => {
"msg": "3"
}
最后我们可以根据您的要求修复您的assert
任务:
- name: "File output | verification"
vars:
watch_regex: '(?:^|W)(test)(?:$|W)'
assert:
that:
- testing_parse.stdout | regex_findall(watch_regex) | length > 1
fail_msg: "Exiting now."
success_msg: "Proceeding with task."