【问题标题】:How to create an empty file with Ansible?如何使用 Ansible 创建一个空文件?
【发布时间】:2025-11-28 03:45:02
【问题描述】:

使用 Ansible 创建空文件的最简单方法是什么?我知道我可以将一个空文件保存到files 目录中,然后将其复制到远程主机,但我觉得这有点不满意。

另一种方法是触摸远程主机上的文件:

- name: create fake 'nologin' shell
  file: path=/etc/nologin state=touch owner=root group=sys mode=0555

但是后来文件每次都被触动,在日志中显示为黄线,这也不尽人意……

对于这个简单的问题有没有更好的解决方案?

【问题讨论】:

    标签: file ansible


    【解决方案1】:

    文件模块的文档说

    如果是state=file,如果文件不存在,则不会创建该文件,如果您想要该行为,请查看复制或模板模块。

    所以我们使用copy module,使用force=no仅在文件尚不存在时创建一个新的空文件(如果文件存在,则保留其内容)。

    - name: ensure file exists
      copy:
        content: ""
        dest: /etc/nologin
        force: no
        group: sys
        owner: root
        mode: 0555
    

    这是一个声明式且优雅的解决方案。

    【讨论】:

    • 很好的答案,很好奇如何使用您提供的相同结构创建两个空文件?
    • 如果父目录不存在,有没有办法让它创建父目录,还是我需要单独创建?
    • 您需要确保父目录存在且可写。见*.com/questions/22844905/…
    • 如果权限不正确并且文件已经存在,这将不会修复权限。见github.com/ansible/ansible/issues/7490 ...不幸的是,似乎只有2.7+才有更好的方法。
    【解决方案2】:

    这样的事情(首先使用stat 模块收集有关它的数据,然后使用条件过滤)应该可以工作:

    - stat: path=/etc/nologin
      register: p
    
    - name: create fake 'nologin' shell
      file: path=/etc/nologin state=touch owner=root group=sys mode=0555
      when: p.stat.exists is defined and not p.stat.exists
    

    您也可以利用changed_when 功能。

    【讨论】:

    • 也许应该是:"when: not p.stat.exists"
    【解决方案3】:

    另一个选项,使用命令模块:

    - name: Create file
      command: touch /path/to/file
      args:
        creates: /path/to/file
    

    'creates' 参数确保在文件存在时不执行此操作。

    【讨论】:

    • 你应该尽可能避免命令,因为它不是幂等的。 ryaneschinger.com/blog/…
    • @redshark1802 同意。虽然在这种情况下,任务是幂等的,因为如果“/path/to/file”已经存在,它将不会被执行。我认为 René Pijl 的解决方案是三个*答案中更像 Ansible 的解决方案,如果您需要设置所有权、模式等,绝对应该使用它。
    【解决方案4】:

    文件模块提供了在不修改时间的情况下触摸文件的方法。

    - name: Touch again the same file, but dont change times this makes the task idempotent
      file:
        path: /etc/foo.conf
        state: touch
        mode: u+rw,g-wx,o-rwx
        modification_time: preserve
        access_time: preserve
    
    

    参考: https://docs.ansible.com/ansible/latest/modules/file_module.html

    【讨论】:

    • 这是 ansible 2.7+ 的正确答案,但是其中缺少重要信息。
    【解决方案5】:

    在接受的答案的基础上,如果您希望在每次运行时检查文件的权限,并且如果文件存在则相应地更改这些权限,或者如果文件不存在则只创建文件,您可以使用以下命令:

    - stat: path=/etc/nologin
      register: p
    
    - name: create fake 'nologin' shell
      file: path=/etc/nologin 
            owner=root
            group=sys
            mode=0555
            state={{ "file" if  p.stat.exists else "touch"}}
    

    【讨论】:

    • 这个答案很棒,因为它为您提供了在文件不存在时定义文件属性的灵活性。
    【解决方案6】:

    file: path=/etc/nologin state=touch

    完全等效于触摸(1.4+ 中的新功能) - 如果您不想更改文件时间戳,请使用 stat。

    【讨论】:

    • 不是幂等的,每次执行ansible playbook都会修改文件日期。
    • @Jérôme B Ansible 2.7 中的新功能:您可以使用 file: path=/etc/nologin state=touch modification_time=preserve access_time=preserve 使其具有幂等性。
    【解决方案7】:

    事实证明,我没有足够的声誉将此作为评论,这将是一个更合适的地方:

    回复。 AllBlackt 的回答,如果您更喜欢 Ansible 的多行格式,您需要调整 state 的引用(我花了几分钟解决这个问题,所以希望这能加快其他人的速度),

    - stat:
        path: "/etc/nologin"
      register: p
    
    - name: create fake 'nologin' shell
      file:
        path: "/etc/nologin"
        owner: root
        group: sys
        mode: 0555
        state: '{{ "file" if  p.stat.exists else "touch" }}'
    

    【讨论】:

      【解决方案8】:

      如果文件不存在则更改。创建空文件。

      - name: create fake 'nologin' shell
        file:
          path: /etc/nologin
          state: touch
        register: p
        changed_when: p.diff.before.state == "absent"
      

      【讨论】:

        【解决方案9】:

        两个答案的组合,有一个转折。当创建文件或更新权限时,代码将被检测为已更改。

        - name: Touch again the same file, but dont change times this makes the task idempotent
          file:
            path: /etc/foo.conf
            state: touch
            mode: 0644
            modification_time: preserve
            access_time: preserve
          changed_when: >
            p.diff.before.state == "absent" or
            p.diff.before.mode|default("0644") != "0644"
        

        还有一个版本,它还可以更正所有者和组,并在更正这些时检测到它已更改:

        - name: Touch again the same file, but dont change times this makes the task idempotent
          file:
            path: /etc/foo.conf
            state: touch
            state: touch
            mode: 0644
            owner: root
            group: root
            modification_time: preserve
            access_time: preserve
          register: p
          changed_when: >
            p.diff.before.state == "absent" or
            p.diff.before.mode|default("0644") != "0644" or
            p.diff.before.owner|default(0) != 0 or
            p.diff.before.group|default(0) != 0
        

        【讨论】:

        • ansible 2.7+ - 应该提到。
        【解决方案10】:

        为了使用 ad-hoc 命令在远程机器上创建文件

        ansible client -m file -a"dest=/tmp/file state=touch"
        

        如有错误请指正

        【讨论】:

          最近更新 更多