You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Ansible Playbook中通过循环将Shell命令输出写入文件

问题描述

我想把Shell命令的输出加载为变量,结合循环将每个用户的处理结果写入文件。具体是把循环的用户值传入getent命令,执行getent passwd {{item}} |sed -E 's/:[^ ]*:(.)[^ ]* ([^:]*).*/\L,\1\2/'后,期望将结果user1,uone和user2,utwo逐行写入文件,但当前Playbook写入了错误内容。

原Playbook脚本

- hosts: all
  remote_user: root
  gather_facts: no
  tasks:

  - name: Add user variable
    ansible.builtin.shell: getent passwd {{item}} |sed -E 's/:[^ ]*:(.)[^ ]* ([^:]*).*/\L,\1\2/'
    register: getent_result
    ignore_errors: true
    loop:
     - user1
     - user2

  - name: Add user to file.txt
    ansible.builtin.lineinfile:
      path: "/path/to/file/file.txt"
      regexp: '^{{item}}'
      line: '{{getent_result}}'
      insertafter: 'EOF'
      create: yes
    loop:
     - user1
     - user2

实际写入内容

{'msg': 'All items completed', 'changed': True, 'results': [{'stderr_lines': [], 'ansible_loop_var': 'item', 'end': '2023-05-18 13:30:53.434569', 'stderr': '', 'stdout': 'user1,uone', 'changed': True, 'rc': 0, 'start': '2023-05-18 13:30:53.420151', 'failed': False, 'cmd': "getent passwd user1 |sed -E 's/:[^ ]*:(.)[^ ]* ([^:]*).*/\\L,\\1\\2/'", 'item': 'user1', 'delta': '0:00:00.014418', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, 'strip_empty_ends': True, '_raw_params': "getent passwd user1 |sed -E 's/:[^ ]*:(.)[^ ]* ([^:]*).*/\\L,\\1\\2/'", 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin_add_newline': True, 'stdin': None}}, 'stdout_lines': ['user1,uone'], 'ansible_facts': {'discovered_interpreter_python': '/usr/bin/python'}}, {'stderr_lines': [], 'ansible_loop_var': 'item', 'end': '2023-05-18 13:30:54.332020', 'stderr': '', 'stdout': 'user2,utwo', 'changed': True, 'rc': 0, 'failed': False, 'cmd': "getent passwd user2 |sed -E 's/:[^ ]*:(.)[^ ]* ([^:]*).*/\\L,\\1\\2/'", 'item': 'user2', 'delta': '0:00:00.011729', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, 'strip_empty_ends': True, '_raw_params': "getent passwd user2 |sed -E 's/:[^ ]*:(.)[^ ]* ([^:]*).*/\\L,\\1\\2/'", 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin_add_newline': True, 'stdin': None}}, 'stdout_lines': ['user2,utwo'], 'start': '2023-05-18 13:30:54.320291'}]}

期望写入内容

user1,uone
user2,utwo
错误原因

当用loop注册变量时,getent_result是一个包含整个循环执行结果的复合对象,而非单个用户的命令输出。第二个任务直接引用{{getent_result}},会把整个对象的字符串表示写入文件,而不是提取每个用户对应的stdout值。

解决方案

修改第二个任务,循环遍历getent_result.results(存储每个循环项结果的列表),提取每个结果中的stdout字段写入文件:

- hosts: all
  remote_user: root
  gather_facts: no
  tasks:

  - name: 获取用户处理结果
    ansible.builtin.shell: getent passwd {{item}} |sed -E 's/:[^ ]*:(.)[^ ]* ([^:]*).*/\L,\1\2/'
    register: getent_result
    ignore_errors: true
    loop:
     - user1
     - user2

  - name: 将结果写入文件
    ansible.builtin.lineinfile:
      path: "/path/to/file/file.txt"
      regexp: '^{{item.item}}'  # 匹配结果对应的用户名
      line: '{{item.stdout}}'    # 使用每个循环项的标准输出
      insertafter: 'EOF'
      create: yes
    loop: "{{ getent_result.results }}"  # 遍历第一个任务的所有结果项
    when: not item.failed  # 跳过执行失败的项(可选)

简化方案(合并任务)

如果不需要单独保存结果,也可以直接在一个任务中完成命令执行和写入:

- hosts: all
  remote_user: root
  gather_facts: no
  tasks:

  - name: 处理用户并写入文件
    ansible.builtin.lineinfile:
      path: "/path/to/file/file.txt"
      regexp: '^{{item}}'
      line: "{{ lookup('pipe', 'getent passwd ' + item + \" |sed -E 's/:[^ ]*:(.)[^ ]* ([^:]*).*/\\\\L,\\\\1\\\\2/'\") }}"
      insertafter: 'EOF'
      create: yes
    loop:
     - user1
     - user2

内容的提问来源于stack exchange,提问作者keith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 19:47:55