223

I have to check whether a file exists in /etc/. If the file exists then I have to skip the task. Here is the code I am using:

- name: checking the file exists
  command: touch file.txt
  when: $(! -s /etc/file.txt)

13 Answers 13

397

You can first check that the destination file exists or not and then make a decision based on the output of its result:

tasks:
  - name: Check that the somefile.conf exists
    stat:
      path: /etc/file.txt
    register: stat_result

  - name: Create the file, if it doesnt exist already
    file:
      path: /etc/file.txt
      state: touch
    when: not stat_result.stat.exists
Sign up to request clarification or add additional context in comments.

6 Comments

What if the directory does not exist?
If the directory does not exist, then the register stat_result will have a stat_result.state.exists of False (and that's when the second task runs). You can see details of the stat module here: docs.ansible.com/ansible/stat_module.html
when: stat_result.stat.exists is defined and stat_result.stat.exists
what if i want it to be responsive , so when the file is removed after the task is executed the value of stat_result changes automatically
In addition to specifying path, you should also specify get_checksum: false, get_mime: false, and get_attributes: false. Otherwise it's going to do all that extra work by default.
|
52

The stat module will do this as well as obtain a lot of other information for files. From the example documentation:

- stat: path=/path/to/something
  register: p

- debug: msg="Path exists and is a directory"
  when: p.stat.isdir is defined and p.stat.isdir

1 Comment

Looks like in latest versions, there's a warning when using "full text comparisons" like "is" etc instead of "=", "<", ">" etc.
39

This can be achieved with the stat module to skip the task when file exists.

- hosts: servers
  tasks:
    - name: Ansible check file exists.
      stat:
        path: /etc/issue
      register: p
    - debug:
        msg: "File exists..."
      when: p.stat.exists
    - debug:
        msg: "File not found"
      when: p.stat.exists == False

1 Comment

This answer is correct and better than the most voted in this thread. It should be upvoted instead.
22

In general you would do this with the stat module. But the command module has the creates option which makes this very simple:

- name: touch file
  command: touch /etc/file.txt
  args:
    creates: /etc/file.txt

I guess your touch command is just an example? Best practice would be to not check anything at all and let ansible do its job - with the correct module. So if you want to ensure the file exists you would use the file module:

- name: make sure file exists
  file:
    path: /etc/file.txt
    state: touch

3 Comments

state: file does not create files. See docs.ansible.com/ansible/file_module.html
I would consider the first example in this answer the right answer for this question, based on the specific circumstances of the user's question, user's use of the command module, and ansible best practices.
Note that you can make this idempotent by adding modification_time=preserve access_time=preserve. This is definitely the most compact and Ansible-correct way to do this.
7

Discovered that calling stat is slow and collects a lot of info that is not required for file existence check.
After spending some time searching for solution, i discovered following solution, which works much faster:

- raw: test -e /path/to/something && echo -n true || echo -n false
  register: file_exists

- debug: msg="Path exists"
  when: file_exists.stdout == "true"

2 Comments

Please describe in your answer, what was the problem, and how will this snippet solve it, to help others understand this answer
This is excellent for preventing ansible's busted get_url from re-downloading 20GB downloads every time as will happen in certain cases. stat is very slow for this.
6

Like described in the documentation you can check if a file ore directory does exist in the when statement like:

- name: Check file exists
  debug:
    msg: File exists
  when: "'/my/path' is file"

This is not really well documented and the most google searches points to the solution with the stat module.

To check if the path exists ore not you can use:

- debug:
    msg: Path not exists
  when: '/my/path' is not exists

1 Comment

This is on the control host, not the target host.
3

You can use Ansible stat module to register the file, and when module to apply the condition.

- name: Register file
      stat:
        path: "/tmp/test_file"
      register: file_path

- name: Create file if it doesn't exists
      file: 
        path: "/tmp/test_file"
        state: touch
      when: file_path.stat.exists == False

Comments

3

Below is the ansible play which i used to remove the file if the file exists on OS end.

 - name: find out /etc/init.d/splunk file exists or not'
      stat:
        path: /etc/init.d/splunk
      register: splunkresult
      tags:
        - always

    - name: 'Remove splunk from init.d file if splunk already running'
      file:
        path: /etc/init.d/splunk
        state: absent
      when: splunkresult.stat.exists == true
      ignore_errors: yes
      tags:
        - always

I have used play condition as like below

when: splunkresult.stat.exists == true --> Remove the file

you can give true/false based on your requirement

when: splunkresult.stat.exists == false
when: splunkresult.stat.exists == true

Comments

2

I find it can be annoying and error prone to do a lot of these .stat.exists type checks. For example they require extra care to get check mode (--check) working.

Many answers here suggest

  • get and register
  • apply when register expression is true

However, sometimes this is a code smell so always look for better ways to use Ansible, specifically there are many advantages to using the correct module. e.g.

- name: install ntpdate
  package:
    name: ntpdate

or

- file:
    path: /etc/file.txt
    owner: root
    group: root
    mode: 0644

But when it is not possible use one module, also investigate if you can register and check the result of a previous task. e.g.

# jmeter_version: 4.0 
- name: Download Jmeter archive
  get_url:
    url: "http://archive.apache.org/dist/jmeter/binaries/apache-jmeter-{{ jmeter_version }}.tgz"
    dest: "/opt/jmeter/apache-jmeter-{{ jmeter_version }}.tgz"
    checksum: sha512:eee7d68bd1f7e7b269fabaf8f09821697165518b112a979a25c5f128c4de8ca6ad12d3b20cd9380a2b53ca52762b4c4979e564a8c2ff37196692fbd217f1e343
  register: download_result

- name: Extract apache-jmeter
  unarchive:
    src: "/opt/jmeter/apache-jmeter-{{ jmeter_version }}.tgz"
    dest: "/opt/jmeter/"
    remote_src: yes
    creates: "/opt/jmeter/apache-jmeter-{{ jmeter_version }}"
  when: download_result.state == 'file'

Note the when: but also the creates: so --check doesn't error out

I mention this because often these less-than-ideal practices come in pairs i.e. no apt/yum package so we have to 1) download and 2) unzip

Hope this helps

Comments

1

I use this code and it works fine for folders and files. Just make sure there is no trailing spaces after the folder name. If folder exists , the file_exists.stdout will be "true" otherwise it will just be an empty string ""

- name: check filesystem existence
  shell: if [[ -d  "/folder_name" ]]; then echo "true";  fi
  register: file_exists
  
- name: debug data
  debug: 
    msg: "Folder exists"
  when: file_exists.stdout == "true"

Comments

0
vars:
  mypath: "/etc/file.txt"

tasks:
  - name: checking the file exists
    command: touch file.txt
    when: mypath is not exists

3 Comments

You don't explain your answer, and what does when: mypath is not exists mean in this case ? Isn't mypath a simple string ?
Jinja2 template helps here to validate the path. More examples in Ansible Docs
Note this checks for files on the controller, not the remote.
0

A note on relative paths to complement the other answers.

When doing infrastructure as code I'm usually using roles and tasks that accept relative paths, specially for files defined in those roles.

Special variables like playbook_dir and role_path are very useful to create the absolute paths needed to test for existence.

2 Comments

This should be a comment, not an answer
I love that this is an answer. Then it's not buried in the ohter comments. This is very useful information that should be at the top of one's attention.
0

You can use shell commands to check if file exists

  - set_fact:
    file: "/tmp/test_file"

  - name: check file exists
    shell: "ls {{ file }}"
    register: file_path
    ignore_errors: true

  - name: create file if don't exist
    shell: "touch {{ file }}"
    when: file_path.rc != 0

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.