Table of Contents
Go from Ansible beginner to Ansible pro with this full video course.
What does the Ansible file module do?
Ansible’s file module can:
- Create files, directories and symlinks
- name: create an empty file if it doesn't exist
file:
path: $HOME/test_file
state: touch
- Delete files, directories and symlinks
- name: delete a file (or symlink) if it exists
file:
path: $HOME/test_file
state: absent
- Modify permissions and properties of files and directories
- name: modify permissions and properties of a directory (or create it if it doesn't exist)
file:
path: $HOME/test_directory/inner_test_directory
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0755
modification_time: "201812271410.15"
access_time: now
Ansible file Module Video Tutorial
If you prefer watching to reading, here’s a full video tutorial from the TopTechSkills YouTube channel covering a many of the points and examples from this article. Feel free to comment on this article or the video if you have any questions.
state: file vs state: touch
There are 2 states for dealing specifically with files using the file module: state: file and state: touch.
state: fileensures a path is a file, but will throw an error if the path does not exist or if the path is not a file
- name: check file that doesn't exist with state file
file:
path: $HOME/absent_test_file
state: file
fatal: [123.123.123.123]: FAILED! => {"changed": false,
"msg": "file (/home/ubuntu/absent_test_file) is absent, cannot continue",
"path": "/home/ubuntu/absent_test_file", "state": "absent"}
- name: check directory with state file
file:
path: $HOME/test_directory
state: file
fatal: [123.123.123.123]: FAILED! => {"changed": false, "gid": 1000, "group": "ubuntu", "mode": "0775",
"msg": "file (/home/ubuntu/test_directory) is directory, cannot continue", "owner": "ubuntu",
"path": "/home/ubuntu/test_directory", "size": 4096, "state": "directory", "uid": 1000}
state: touchwill create an empty file if a path does not exist and will not throw an error if the path is a directory or symlink
- name: check file that doesn't exist with state touch
file:
path: $HOME/absent_test_file
state: touch
ok: [123.123.123.123] => {
"file_output": {
"changed": true,
"dest": "/home/ubuntu/absent_test_file",
...
"state": "file",
"uid": 1000
}
}
- name: check directory with state touch
file:
path: $HOME/test_directory
state: touch
ok: [123.123.123.123] => {
"file_output": {
"changed": true,
"dest": "/home/ubuntu/test_directory",
...
"state": "directory",
"uid": 1000
}
}
This behavior of state: touch matches the touch command.
Examples
Create a directory or ensure a directory exists
You can ensure a directory exists by setting the state parameter to directory. If the directory already exists, Ansible will do nothing. Note that state: directory behaves like mkdir -p and will create any parent directories if they don’t exist. In the example below, test_directory (the parent directory) will be created in addition to inner_test_directory if it doesn’t already exist.
- name: ensure a directory exists
file:
path: $HOME/test_directory/inner_test_directory
state: directory
Create multiple directories in a loop
Use the loop keyword and {{ item }} to create multiple directories in a loop.
- name: create multiple directories in a loop
file:
path: "$HOME/test_directory/{{ item }}"
state: directory
register: file_output
loop:
- inner_test_directory
- another_test_directory/another_inner_directory
.
└── test_directory
├── another_test_directory
│ └── another_inner_directory
└── inner_test_directory
Delete a directory recursively
You can delete a directory by setting the state parameter to absent. If the directory does not exist, Ansible will do nothing.
- name: delete a directory recursively if it exists
file:
path: $HOME/test_directory
state: absent
Change permissions of a directory
The owner, group and mode parameters of the file module give you fine control over ownership and file permissions. Remember that you will need become: true if you are setting the owner or group to values that don’t match the ansible_user.
The mode parameter accepts the following:
- Octal mode format: e.g.
0755 - Symbolic mode format: e.g.
u=rwx,g=rx,o=rx(whereuis the owner,gis the group, andois others). The permissions arerforread,wfor write andxfor execute.
With octal mode:
- name: modify ownership & permissions of a directory (octal mode)
file:
path: $HOME/test_directory/inner_test_directory
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0755
With symbolic mode (equivalent to 0755):
- name: modify ownership & permissions of a directory (symbolic mode)
file:
path: $HOME/test_directory/inner_test_directory
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: u=rwx,g=rx,o=rx
Setting a different owner with become: true:
- name: change ownership & permissions of directory with become
file:
path: /var/log/nginx
state: directory
owner: root
group: root
mode: 0755
become: true
Change permissions of a directory recursively
You can use the recurse keyword to change directory permissions recursively. This will affect the path, as well as all the files and directories inside it.
- name: modify ownership & permissions of a directory recursively
file:
path: $HOME/test_directory
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0755
recurse: true
Set directories to 0755 and files to 0644 recursively
A common task when ensuring correct file permissions on a system is to recursively apply a mode of 0755 on a directory so that all files and directories inside can be read by all users. Applying a mode of 755 to directories is fine, but applying that mode to files is not good practice because it allows all users to execute them, which is insecure. It’s better practice to set files to a mode of 0644, which lets all users read a file but not execute it.
It’s possible to recursively apply a mode of 0755 to directories and 0644 to files with the file module by using symbolic mode:
- name: recursively set 0755 on directories and 0644 on files
file:
path: $HOME/test_directory
state: directory
mode: u=rwX,g=rX,o=rX
recurse: true
The X (instead of x) will affect only directories or files that already allow execution.
Create a symlink
You can create symlinks by setting the state parameter to link. You will need to set src and dest parameters for the symlink. The src is the original file and dest is the symlink.
- name: create a symlink if it doesn't exist
file:
src: $HOME/test_file
dest: $HOME/test_directory/inner_test_directory/test_file_symlink
state: link
Delete a symlink
You can delete a symlink with the file module in the same way as a file or directory: simply use state: absent.
- name: delete a symlink if it exists
file:
path: $HOME/test_directory/inner_test_directory/test_file_symlink
state: absent
Create an empty file or ensure a file exists
You can ensure a file exists at a certain path by setting state to touch, which will do nothing if a file already exists, or create an empty file if it doesn’t.
- name: create an empty file if it doesn't exist
file:
path: $HOME/test_file
state: touch
Delete a file if it exists
You can delete a file by setting state to absent. If the file doesn’t exist, Ansible will do nothing.
- name: delete a file if it exists
file:
path: $HOME/test_file
state: absent
Update the modified time or access time of a file
Since Ansible 2.7, you can update the access and modified times of a file by using the access_time and modification_time parameters. The parameters accept the following values:
preserve- no change (default when no value is provided)now- set to the current time"YYYYmmddHHMM.SS"- set to a specific time (note the quotation marks, without them Ansible interprets it as a float)
- name: modify access and modified times of a file
file:
path: $HOME/test_file
state: file
access_time: now
modification_time: "201812271410.15"
How to capture file module output
Use the register keyword to capture the output of the file module.
- name: ensure a directory exists
file:
path: $HOME/test_directory/inner_test_directory
state: directory
register: file_output
- debug: var=file_output
The debug task above will output the following:
ok: [123.123.123.123] => {
"file_output": {
"changed": true,
"diff": {
"after": {
"path": "/home/ubuntu/test_directory/inner_test_directory",
"state": "directory"
},
"before": {
"path": "/home/ubuntu/test_directory/inner_test_directory",
"state": "absent"
}
},
"failed": false,
"gid": 1000,
"group": "ubuntu",
"mode": "0775",
"owner": "ubuntu",
"path": "/home/ubuntu/test_directory/inner_test_directory",
"size": 4096,
"state": "directory",
"uid": 1000
}
}
How to capture file module output from a loop
When using the file module in a loop, the output of each item in the loop will go into the results key of the registered variable.
- name: create multiple directories in a loop
file:
path: "$HOME/test_directory/{{ item }}"
state: directory
register: file_output
loop:
- inner_test_directory
- another_test_directory/another_inner_directory
- debug: var=file_output
ok: [123.123.123.123] => {
"file_output": {
"changed": true,
"msg": "All items completed",
"results": [
{
...
"changed": true,
"diff": {
"after": {
"path": "/home/ubuntu/test_directory/inner_test_directory",
"state": "directory"
},
"before": {
"path": "/home/ubuntu/test_directory/inner_test_directory",
"state": "absent"
}
},
"failed": false,
"gid": 1000,
"group": "ubuntu",
"invocation": {...},
"item": "inner_test_directory",
"mode": "0775",
"owner": "ubuntu",
"path": "/home/ubuntu/test_directory/inner_test_directory",
"size": 4096,
"state": "directory",
"uid": 1000
},
{
...
"changed": true,
"diff": {
"after": {
"path": "/home/ubuntu/test_directory/another_test_directory/another_inner_directory",
"state": "directory"
},
"before": {
"path": "/home/ubuntu/test_directory/another_test_directory/another_inner_directory",
"state": "absent"
}
},
"failed": false,
"gid": 1000,
"group": "ubuntu",
"invocation": {...},
"item": "another_test_directory/another_inner_directory",
"mode": "0775",
"owner": "ubuntu",
"path": "/home/ubuntu/test_directory/another_test_directory/another_inner_directory",
"size": 4096,
"state": "directory",
"uid": 1000
}
]
}
}
Further reading
Ansible file Module on Ansible Docs

