21

How can I use Jekyll to test for the existence of a file?

To clarify, I want to run an {% if %} statement to check if an image file exists with the same name as the page I am on.

On my page in the YAML front matter:

----
  reference-design: true
----

In my layout:

{% if page.reference-design %}
    {% assign filename = page.path | remove_first: '.html' %}
    <!-- How can I check if file actually exists? -->
    <img src="images/reference_designs/{{ filename }}.png">
{% endif %}
rocambille
  • 15,398
  • 12
  • 50
  • 68
Wolfr
  • 5,055
  • 4
  • 25
  • 31

4 Answers4

24

As of Jekyll 2, all site files are available via site.static_files. You can use this to check if a file exists. For example:

{% for static_file in site.static_files %}
    {% if static_file.path == '/favicon.ico' %}
        {% assign favicon = true %}
    {% endif %}
{% endfor %}
Jonathan
  • 18,229
  • 10
  • 57
  • 56
  • 8
    Incredibly inefficient. – KFunk May 16 '17 at 23:59
  • 1
    @KFunk why? Checking file existence involves I/O and could very well be slower than this until you have quite a lot of static files. Also, if it's the only solution, I'd take it. – autra Jul 28 '17 at 14:50
  • 13
    @KFunk Probably, but performance isn't a super big concern with Jekyll, since you only do the compiling stage once. It ultimately results in plain old static HTML. If my build process takes a few more seconds, I honestly don't care. – Jonathan Aug 01 '17 at 13:57
  • At least in Jekyll 3, this does for work for checking if a file exists in `_includes`, exists in a collection, or really other files that are handled by Jekyll. However, it does work for things like assets. – vossad01 Aug 04 '17 at 20:11
  • 2
    What @vossad01 meant was, this method won't work for anything the contains front matter. Quoting from Jekyll website: "A static file is a file that does not contain any front matter. These include images, PDFs, and other un-rendered content." OP wants to search for image so it's fine to use this method. – Abel Cheung Jun 21 '19 at 16:28
  • Indeed performance isn't a super big deal with a pre-compiled site, but I interpretted "incredibly inefficient" as "really bad dev experience/ergonomics", which it definitely is. [This guy thought of a less ugly version](https://devopsx.com/jekyll-check-if-file-exists/): `{% assign file = site.static_files | where: "path", some_path | first %}` – V. Rubinetti Feb 15 '23 at 15:12
2

I had a similar problem to solve, but specifically looking for videos that matched the a specific directory / filename based on the markdown file.

Using file.size allowed me to test if the file (actually) exists.

 {% for video in site.video-demos %}
      {% assign path = page.id | replace: page.slug , ""  | prepend: '/assets/media/video' | append: video.directory | append: page.slug | append: ".mp4"  %}
      {% assign file_exists = site.static_files | where: "path", path  %}
      {% if file_exists.size != 0 %}
        {% include video-player.html filename = path title = video.title %}
      {% endif %}
 {% endfor %}

It loops through an array from my config to get part of the directory structure:

video-demos:
- title: iOS Voiceover Safari
  directory: ios/
- title: Android Talkback Chrome
  directory: android/
- title: Windows Jaws Chrome
  directory: jaws/
- title: Windows NVDA Chrome
  directory: nvda/
- title: MacOS Voiceover Safari
  directory: macos/
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
1

This plugin worked for me: https://github.com/Wolfr/jekyll_file_exists

After you install it, you can use it like:

{% if page.reference-design %}
    {% assign filename = page.path | remove_first: '.html' %}
    {% capture img_exists %}{% file_exists {{ filename }}.png %}{% endcapture %}

    {% if img_exists == "true" %}
        <img src="images/reference_designs/{{ filename }}.png">
    {% endif %}
{% endif %}
Bill Mei
  • 717
  • 1
  • 10
  • 22
-3

Read http://ecommerce.shopify.com/c/ecommerce-design/t/testing-if-a-file-exists-29624. Also you might be able to play with capture.

Nathan Lilienthal
  • 864
  • 1
  • 10
  • 16