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.

How to rename a file or directory using an Ansible task on a remote system?
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 utilitymv.
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
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 Ansiblecode
- 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
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: trueUsing 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: trueRename 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: trueRename Directory
- command:
cmd: mv /opt/myapp-old /opt/myapp-new
removes: /opt/myapp-old
creates: /opt/myapp-new
become: trueRename 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: trueRename 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: trueMove File to Another Directory
- command:
cmd: mv /tmp/downloaded-app.tar.gz /opt/releases/
removes: /tmp/downloaded-app.tar.gz
become: trueAtomic 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: trueWhy No "rename" Module?
Ansible doesn't have a dedicated rename/move module because:
command: mvis simple and well-understoodcopy+file: absentprovides 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: localhostRelated Articles
- skipping tasks with Ansible when
- Ansible inventory complete reference
- ansible.builtin.file guide
- Ansible Roles Guide
See also
Category: troubleshooting
Watch the video: Ansible Rename File: Move & Rename Files with copy + file Modules — Video Tutorial