assert模块:如果字符串只被发现一次,是否可能失败?



我有一些正在解析的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'

这意味着:

  1. 检查字符串testing_parse.stdout是否在词法上优于或等于字符串'2'
  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."

相关内容

最新更新