AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible Rename File: Move & Rename Files with copy + file Modules

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

How to rename files and directories in Ansible using copy and file modules. Move files, rename with register, use command module.

Ansible Rename File: Move & Rename Files with copy + file Modules

How to rename a file or directory using an Ansible task on a remote system?

I'm going to show you a live Playbook with some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.

See also: Ansible Create Symlink: file Module with state=link (Guide)

Ansible rename file/directory

First of all let me demystify that I'd like to propose a solution using only Ansible native modules, so no shell module to invoke the Unix utility mv. Today we're talking about Ansible two modules copy and file The full names are ansible.builtin.copy and ansible.builtin.file which means are part of the collection of modules "builtin" with ansible and shipped with it. Both are these modules are pretty stable and out for years. The purpose of the copy module is to copy files to remote locations. Once the file is successfully copied we could use the module file to delete the source file.

Parameters

Module copy

• dest path - destination • src string - source • remote_src boolean - no / yes

Module file

• path string (dest, name) - file path • state string - file/absent/directory/hard/link/touch

The parameter list is pretty wide but I'll summarize the most useful. The only required parameter is "dest" which specifies the destination path. The "src" specifies the source file presumed in the controller host. It could be a relative or absolute path. From version 2.0, in the copy module, you can use the "remote_src" parameter. If True it will search the file in the remote/target machine for the src. From version 2.8 copy module remote_src supports recursive copying. The only required is "path", where you specify the filesystem path of the file you're going to edit. The state defines the type of object we are modifying, the default is "file" but we could also handle directories, hardlink, symlink, or only update the access time with the "touch" option. For our use case, we are going to use the "absent" option.

See also: Ansible Create File with Content: copy Module content Parameter

Demo

Let's jump in a real-life playbook to rename files or directories with Ansible

code

• rename/file.yml
---
- name: rename file or directory
  hosts: all
  vars:
    mysrc: "~/foo"
    mydst: "~/bar"
  tasks:
    - name: Check if file exists
      ansible.builtin.stat:
        path: "{{ mysrc }}"
      register: check_file_name
    - name: print debug
      ansible.builtin.debug:
        var: check_file_name
    - name: Copy file with new name
      ansible.builtin.copy:
        remote_src: true
        src: "{{ mysrc }}"
        dest: "{{ mydst }}"
      when: check_file_name.stat.exists
    - name: Remove old file
      ansible.builtin.file:
        path: "{{ mysrc }}"
        state: absent
      when: check_file_name.stat.exists

execution

• output file does not exist:
$ ansible-playbook -i Playbook/inventory rename/file.yml
PLAY [rename file or directory] *****************************************************************************
TASK [Gathering Facts] **************************************************************************************
ok: [demo.example.com]
TASK [Check if file exists] *********************************************************************************
ok: [demo.example.com]
TASK [print debug] ******************************************************************************************
ok: [demo.example.com] => {
    "check_file_name": {
        "changed": false,
        "failed": false,
        "stat": {
            "exists": false
        }
    }
}
TASK [Copy file with new name] ******************************************************************************
skipping: [demo.example.com]
TASK [Remove old file] **************************************************************************************
skipping: [demo.example.com]
PLAY RECAP **************************************************************************************************
demo.example.com           : ok=3    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0
• output file exists:
$ ansible-playbook -i Playbook/inventory rename/file.yml
PLAY [rename file or directory] *****************************************************************************
TASK [Gathering Facts] **************************************************************************************
ok: [demo.example.com]
TASK [Check if file exists] *********************************************************************************
ok: [demo.example.com]
TASK [print debug] ******************************************************************************************
ok: [demo.example.com] => {
    "check_file_name": {
        "changed": false,
        "failed": false,
        "stat": {
            "atime": 1632319723.592112,
            "attr_flags": "",
            "attributes": [],
            "block_size": 4096,
            "blocks": 0,
            "charset": "binary",
            "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
            "ctime": 1632319723.592112,
            "dev": 64768,
            "device_type": 0,
            "executable": false,
            "exists": true,
            "gid": 10,
            "gr_name": "wheel",
            "inode": 134764246,
            "isblk": false,
            "ischr": false,
            "isdir": false,
            "isfifo": false,
            "isgid": false,
            "islnk": false,
            "isreg": true,
            "issock": false,
            "isuid": false,
            "mimetype": "inode/x-empty",
            "mode": "0644",
            "mtime": 1632319723.592112,
            "nlink": 1,
            "path": "/home/devops/foo",
            "pw_name": "devops",
            "readable": true,
            "rgrp": true,
            "roth": true,
            "rusr": true,
            "size": 0,
            "uid": 1001,
            "version": "1745015340",
            "wgrp": false,
            "woth": false,
            "writeable": true,
            "wusr": true,
            "xgrp": false,
            "xoth": false,
            "xusr": false
        }
    }
}
TASK [Copy file with new name] ******************************************************************************
changed: [demo.example.com]
TASK [Remove old file] **************************************************************************************
changed: [demo.example.com]
PLAY RECAP **************************************************************************************************
demo.example.com           : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
• output directory exists:
$ ansible-playbook -i Playbook/inventory rename/file.yml
PLAY [rename file or directory] *****************************************************************************
TASK [Gathering Facts] **************************************************************************************
ok: [demo.example.com]
TASK [Check if file exists] *********************************************************************************
ok: [demo.example.com]
TASK [print debug] ******************************************************************************************
ok: [demo.example.com] => {
    "check_file_name": {
        "changed": false,
        "failed": false,
        "stat": {
            "atime": 1632319779.5021598,
            "attr_flags": "",
            "attributes": [],
            "block_size": 4096,
            "blocks": 0,
            "charset": "binary",
            "ctime": 1632319779.5021598,
            "dev": 64768,
            "device_type": 0,
            "executable": true,
            "exists": true,
            "gid": 10,
            "gr_name": "wheel",
            "inode": 898820,
            "isblk": false,
            "ischr": false,
            "isdir": true,
            "isfifo": false,
            "isgid": false,
            "islnk": false,
            "isreg": false,
            "issock": false,
            "isuid": false,
            "mimetype": "inode/directory",
            "mode": "0755",
            "mtime": 1632319779.5021598,
            "nlink": 2,
            "path": "/home/devops/foo",
            "pw_name": "devops",
            "readable": true,
            "rgrp": true,
            "roth": true,
            "rusr": true,
            "size": 6,
            "uid": 1001,
            "version": "1317302979",
            "wgrp": false,
            "woth": false,
            "writeable": true,
            "wusr": true,
            "xgrp": true,
            "xoth": true,
            "xusr": true
        }
    }
}
TASK [Copy file with new name] ******************************************************************************
ok: [demo.example.com]
TASK [Remove old file] **************************************************************************************
changed: [demo.example.com]
PLAY RECAP **************************************************************************************************
demo.example.com           : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

code with ❤️ in GitHub

Conclusion

Now you know how to rename file or directory with Ansible.

See also: Ansible Create Empty File: Touch Files with file Module (Guide)

Using command (Simplest)

- ansible.builtin.command:
    cmd: mv /opt/old-name.conf /opt/new-name.conf
    removes: /opt/old-name.conf
    creates: /opt/new-name.conf
  become: true

Using copy + file (Idempotent)

# Step 1: Copy to new name
- ansible.builtin.copy:
    src: /opt/old-name.conf
    dest: /opt/new-name.conf
    remote_src: true
  become: true

# Step 2: Remove old file - ansible.builtin.file: path: /opt/old-name.conf state: absent become: true

Rename with Stat Check

- stat:
    path: /opt/old-name.conf
  register: old_file

- command: mv /opt/old-name.conf /opt/new-name.conf when: old_file.stat.exists become: true

Rename Directory

- command:
    cmd: mv /opt/myapp-old /opt/myapp-new
    removes: /opt/myapp-old
    creates: /opt/myapp-new
  become: true

Rename Multiple Files

- command:
    cmd: "mv {{ item.old }} {{ item.new }}"
    removes: "{{ item.old }}"
    creates: "{{ item.new }}"
  loop:
    - { old: /opt/app.conf.bak, new: /opt/app.conf }
    - { old: /opt/db.conf.bak, new: /opt/db.conf }
  become: true

Rename with Pattern (Shell)

# Rename all .txt to .bak
- shell: |
    for f in /opt/configs/*.txt; do
      mv "$f" "${f%.txt}.bak"
    done
  args:
    executable: /bin/bash
  become: true

Move File to Another Directory

- command:
    cmd: mv /tmp/downloaded-app.tar.gz /opt/releases/
    removes: /tmp/downloaded-app.tar.gz
  become: true

Atomic Rename (Same Filesystem)

# mv on same filesystem is atomic (instant, no partial state)
- command: mv /opt/myapp/current /opt/myapp/previous
  ignore_errors: true
  become: true

- command: mv /opt/myapp/new-release /opt/myapp/current become: true

Why No "rename" Module?

Ansible doesn't have a dedicated rename/move module because: • command: mv is simple and well-understood • copy + file: absent provides idempotency • A rename module would just wrap os.rename() with little added value

FAQ

Is command: mv idempotent?

Not by itself. Add removes: and creates: parameters to make it idempotent — the task skips if the source is gone or destination exists.

copy + file vs command mv?

copy + file copies data (slow for large files, works across filesystems). mv is instant on the same filesystem. For large files, use command: mv.

Can I rename files on the Ansible controller?

- command: mv /local/old /local/new
  delegate_to: localhost

Related Articles

skipping tasks with Ansible whenAnsible inventory complete referenceansible.builtin.file guideAnsible Roles Guide

See also

Create ISO image from Files and Folders - Ansible module iso_create

Category: troubleshooting

Watch the video: Ansible Rename File: Move & Rename Files with copy + file Modules — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home