Constructing file paths that are platform independent


I wish to construct platform independent file paths within a template for a theme used by users across multiple operating systems. For example, a path would need to be constructed as /x/y/z on *nix or \x\y\z on Windows.

I don’t believe that Hugo’s Path template functionality currently supports constructing platform independent file paths.

Therefore, what would be the optimal workaround? I’m thinking either check for an OS dependent environment variable or grab the directory separator by calling one of Hugo’s functions that provides a file path as output.


What is your use case?

Generally, having access to a template variable containing the OS string and/or directory separator (/ or \) would be helpful to enable a number of applications.

Specifically, I am attempting to solve . The Academic theme uses file paths of content files to handle advanced relationships between various pages, kind of like a graph equivalent to Hugo’s taxonomies.

It works fine on *nix hosts (which is obviously pretty much all hosts) but currently the relationship manager breaks on Windows due to the hard coded directory separator that is concatenated to form paths to content files.

@bep to further clarify, the code linked above is attempting to determine if a page is a page bundle, and if so, get the directory name of the page bundle. Currently, I believe Hugo can only directly provide the full dir path (.File.Dir). It would be nice to have something like .File.PageBundleName as .File.LogicalName will just return index when run within a page bundle.

Alternatively, if OS or directory separator can be provided in a Hugo template var, this would enable the theme designer to compute the Page Bundle Name.

What do you need the directory name for?

@neutreno – what if you did something like this, and if it contains / then Unix-like, else Windows.

{{ getenv "PATH" }}

You could play around with other env vars, I just used PATH here since all OSs have it.

I solved it with the following:

{{ $dir_sep := substr .Dir -1 1 }}
{{ $bundle := delimit (last 1 (split (substr .Dir 0 -1) $dir_sep)) "" }}

This work around is based on certain assumptions and is not that elegant, so it would still be nice to have one or more of the 3 above suggestions built into Hugo.

The 3 suggestions concern implementing one or more of:

  1. a template var for OS string (giving something like Windows, Mac, or Linux)
  2. a var for file system dir separator (/ or \) to enable construction of file paths
  3. a .File.PageBundleName var for bundle name

What you want is probably .File.ContentBaseName

That said, you can do path manipulation with and friends.

A general tip when asking for help on this forum: Tell us what you try to solve, not how you try to solve it.


Thanks @bep!

I wasn’t aware of .File.ContentBaseName as it’s not in the docs - I assume it was added fairly recently. It looks like .File.ContentBaseName performs exactly what I was after by obtaining the content name irrespective of whether the page is a bundle or not :smile:

Path.dir and associated functions also look really handy as they convert the path to *nix form as opposed to .Dir which would require OS dependent processing in this scenario.

1 Like

Wrote a short post on File Variables. It basically mirrors what’s in the docs, but the included shortcode may be useful to you.