12

当元素包含字符串时,我试图在 Jinja2 中的 ansible 中过滤列表,但 Jinja 文档似乎不够清晰,我无法弄清楚。

这是我到目前为止所拥有的:

- name: run script
  command: /usr/tmp/run_script.py
  register: script_results

- name: display run info
  debug:
    var: "{{script_results.stdout_lines | select(\"'running script' in script_results.stdout_lines\") }}"

但我得到的只是错误:

"<generator object _select_or_reject at 0x13851e0>": "VARIABLE IS NOT DEFINED!"

例如,如果stdout_lines包含["apples","running script one","oranges","running script two"],我想打印

running script one
running script two

他们有select文档和 built-in-tests 的文档,但是他们不显示“in”测试,而且我不知道它们在这个 ansible 变量的上下文中是如何工作的。

我试着像这样解决它:

- name: display run info
  debug:
    var: item
  with_items: "{{script_results.stdout_lines}}"
  when: "'running script' in item"

但这会为每条未通过测试的行显示“跳过”……有点违背了目的!

4

5 回答 5

20

select过滤器将采用另一个过滤器。就像在 docs中一样odd,它将只返回列表的奇数元素。您要组合的过滤器selectequalto

现在事情就是这样。Ansible 捆绑了一个非常旧的 Jinja2 版本,它根本不包含equalto过滤器。是的,除非您想过滤奇数元素,否则它会变得毫无用处。(历史上没有人想要……)

此外,我还无法使自定义过滤器插件在 Ansible 2 中工作。所以你几乎被迫一起破解一些丑陋的东西。

helloV 已经展示了一个选项。这是另一个想法:

- name: run script
  shell: /usr/tmp/run_script.py | grep "running script"
  register: script_results

更新:

我最近发现您可以将match(不是标准的 Jinja2 过滤器,而是由 Ansible 添加)与select. 那是eualto过滤器的一个很好的替代品,而且您可以使用正则表达式。这应该有效:

{{ script_results.stdout_lines | select("match", ".*running script.*") }}
于 2016-02-09T04:04:47.540 回答
4

我知道可能有不止一种方法可以做到这一点。这对你有用吗?

  - debug: var={{item}}
    when: item.find('running script') > -1
    with_items: script_results.stdout_lines
于 2016-02-09T01:05:53.340 回答
1

我最终编写了一个 python 脚本来完成它,因为我无法获得 ansible 或 Ancient-jinja2 来进行切割。

Ansible 任务:

- name: gather run info
  command: "{{role_path}}/files/print_results.py {{script_results.stdout_lines}}"
  register: script_print_results
  delegate_to: 127.0.0.1
  run_once: true

- name: display run info
  debug:
    var: script_print_results.stdout_lines
  delegate_to: 127.0.0.1
  run_once: true

Python脚本:

for result_line in sys.argv[1:]:
    if "running script:" in result_line:
        print result_line[1:-1]
于 2016-02-09T17:23:01.130 回答
1

我知道这是一个旧线程,但我也在寻找答案,我能够使用 if in 方法。我认为您遇到的另一个问题是如何显示结果列表。您可以直接在 ansible 模块中执行 jinja 循环,例如调试。当然,由于 Ansible 在使用 debug 呈现数据方面非常糟糕,您也可以使用带有管道 (|) 的 blockinfile 模块。希望这对其他人有所帮助并提供另一种选择。

- debug:
    msg: |
      {% for item in (script_results.stdout_lines) %}
        {% if 'running script' in item %}
        {{ item }}
        {% endif %}
      {% endfor %}
  tags: debug

或将过滤后的数据添加到文件中:

- name: Update the scriptStatus file.
  delegate_to: localhost
  run_once: TRUE
  blockinfile:
    path: '/tmp/scriptStatus.txt'
    block: |
     {% for item in (script_results.stdout_lines) %}
        {% if 'running script' in item %}
        {{ item }}
        {% endif %}
      {% endfor %}
  tags: chkScripts
于 2022-01-10T20:21:35.730 回答
1

set_fact您可以使用新列表的元素构建新列表并打印。

- hosts: localhost
  gather_facts: false
  vars:
    script_stdout_lines:
      - apples
      - running script one
      - oranges
      - running script two
  tasks:
    - set_fact:
        new_list: "{{ new_list | default([]) + [item] }}"
      with_items: "{{ script_stdout_lines }}"
      when: '"running script" in item'
    - debug: var=new_list

结果:

TASK [set_fact] *********************************************************************************************************************
skipping: [localhost] => (item=apples) 
ok: [localhost] => (item=running script one)
skipping: [localhost] => (item=oranges) 
ok: [localhost] => (item=running script two)

TASK [debug] ************************************************************************************************************************
ok: [localhost] => {
    "new_list": [
        "running script one",
        "running script two"
    ]
}

skipping它在操作期间打印,set_fact但最后它提供了一个包含唯一匹配项目的新列表。

于 2019-06-20T12:46:26.800 回答