Path — Elixir v1.18.3 (original) (raw)

This module provides conveniences for manipulating or retrieving file system paths.

The functions in this module may receive chardata as arguments and will always return a string encoded in UTF-8. Chardata is a string or a list of characters and strings, see IO.chardata/0. If a binary is given, in whatever encoding, its encoding will be kept.

The majority of the functions in this module do not interact with the file system, except for a few functions that require it (like wildcard/2 and expand/1).

Summary

Functions

Converts the given path to an absolute one.

Builds a path from relative_to to path.

Returns the last component of the path or the path itself if it does not contain any directory separators.

Returns the last component of path with the extensionstripped.

Returns the directory component of path.

Converts the path to an absolute one, expanding any . and .. components and a leading ~.

Expands the path relative to the path given as the second argument expanding any . and .. characters.

Returns the extension of the last component of path.

Forces the path to be a relative path.

Returns the direct relative path from path in relation to cwd.

Convenience to get the path relative to the current working directory.

Returns the path with the extension stripped.

Returns the path with the extension stripped.

Returns a relative path that is protected from directory-traversal attacks.

safe_relative_to(path, cwd) deprecated

Returns a relative path that is protected from directory-traversal attacks.

Splits the path into a list at the path separator.

Traverses paths according to the given glob expression and returns a list of matches.

Types

Functions

Converts the given path to an absolute one.

Unlike expand/1, no attempt is made to resolve .., ., or ~.

Examples

Unix-like operating systems

Path.absname("foo")
#=> "/usr/local/foo"

Path.absname("../x")
#=> "/usr/local/../x"

Windows

Path.absname("foo")
#=> "D:/usr/local/foo"

Path.absname("../x")
#=> "D:/usr/local/../x"

@spec absname(t(), t() | (-> t())) :: binary()

Builds a path from relative_to to path.

If path is already an absolute path, relative_to is ignored. See alsorelative_to/3. relative_to is either a path or an anonymous function, which is invoked only when necessary, that returns a path.

Unlike expand/2, no attempt is made to resolve .., . or ~.

Examples

iex> Path.absname("foo", "bar")
"bar/foo"

iex> Path.absname("../x", "bar")
"bar/../x"

iex> Path.absname("foo", fn -> "lazy" end)
"lazy/foo"

Returns the last component of the path or the path itself if it does not contain any directory separators.

Examples

iex> Path.basename("foo")
"foo"

iex> Path.basename("foo/bar")
"bar"

iex> Path.basename("lib/module/submodule.ex")
"submodule.ex"

iex> Path.basename("/")
""

@spec basename(t(), t()) :: binary()

Returns the last component of path with the extensionstripped.

This function should be used to remove a specific extension which may or may not be there.

Examples

iex> Path.basename("~/foo/bar.ex", ".ex")
"bar"

iex> Path.basename("~/foo/bar.exs", ".ex")
"bar.exs"

iex> Path.basename("~/foo/bar.old.ex", ".ex")
"bar.old"

Returns the directory component of path.

Examples

iex> Path.dirname("/foo/bar.ex")
"/foo"

iex> Path.dirname("/foo/bar/baz.ex")
"/foo/bar"

iex> Path.dirname("/foo/bar/")
"/foo/bar"

iex> Path.dirname("bar.ex")
"."

Converts the path to an absolute one, expanding any . and .. components and a leading ~.

If a relative path is provided it is expanded relatively to the current working directory.

Examples

Path.expand("/foo/bar/../baz")
#=> "/foo/baz"

Path.expand("foo/bar/../baz")
#=> "$PWD/foo/baz"

@spec expand(t(), t()) :: binary()

Expands the path relative to the path given as the second argument expanding any . and .. characters.

If the path is already an absolute path, relative_to is ignored.

Note that this function treats a path with a leading ~ as an absolute one.

The second argument is first expanded to an absolute path.

Examples

# Assuming that the absolute path to baz is /quux/baz
Path.expand("foo/bar/../bar", "baz")
#=> "/quux/baz/foo/bar"

Path.expand("foo/bar/../bar", "/baz")
#=> "/baz/foo/bar"

Path.expand("/foo/bar/../bar", "/baz")
#=> "/foo/bar"

Returns the extension of the last component of path.

For filenames starting with a dot and without an extension, it returns an empty string.

See basename/1 and rootname/1 for related functions to extract information from paths.

Examples

iex> Path.extname("foo.erl")
".erl"

iex> Path.extname("~/foo/bar")
""

iex> Path.extname(".gitignore")
""

@spec join([t(), ...]) :: binary()

Joins a list of paths.

This function should be used to convert a list of paths to a path. Note that any trailing slash is removed when joining.

Raises an error if the given list of paths is empty.

Examples

iex> Path.join(["~", "foo"])
"~/foo"

iex> Path.join(["foo"])
"foo"

iex> Path.join(["/", "foo", "bar/"])
"/foo/bar"

Joins two paths.

The right path will always be expanded to its relative format and any trailing slash will be removed when joining.

Examples

iex> Path.join("foo", "bar")
"foo/bar"

iex> Path.join("/foo", "/bar/")
"/foo/bar"

The functions in this module support chardata, so giving a list will treat it as a single entity:

iex> Path.join("foo", ["bar", "fiz"])
"foo/barfiz"

iex> Path.join(["foo", "bar"], "fiz")
"foobar/fiz"

Use join/1 if you need to join a list of paths instead.

Forces the path to be a relative path.

If an absolute path is given, it is stripped from its root component.

Examples

Unix-like operating systems

Path.relative("/usr/local/bin")   #=> "usr/local/bin"
Path.relative("usr/local/bin")    #=> "usr/local/bin"
Path.relative("../usr/local/bin") #=> "../usr/local/bin"

Windows

Path.relative("D:/usr/local/bin") #=> "usr/local/bin"
Path.relative("usr/local/bin")    #=> "usr/local/bin"
Path.relative("D:bar.ex")         #=> "bar.ex"
Path.relative("/bar/foo.ex")      #=> "bar/foo.ex"

Returns the direct relative path from path in relation to cwd.

In other words, this function attempts to return a path such thatPath.expand(result, cwd) points to path. This function aims to return a relative path whenever possible, but that's not guaranteed:

This function expands . and .. entries without traversing the file system, so it assumes no symlinks between the paths. Seesafe_relative_to/2 for a safer alternative.

Options

Examples

With relative cwd

If both paths are relative, a minimum path is computed:

Path.relative_to("tmp/foo/bar", "tmp")      #=> "foo/bar"
Path.relative_to("tmp/foo/bar", "tmp/foo")  #=> "bar"
Path.relative_to("tmp/foo/bar", "tmp/bat")  #=> "../foo/bar"

If an absolute path is given with relative cwd, it is returned as:

Path.relative_to("/usr/foo/bar", "tmp/bat")  #=> "/usr/foo/bar"

With absolute cwd

If both paths are absolute, a relative is computed if possible, without traversing up:

Path.relative_to("/usr/local/foo", "/usr/local")      #=> "foo"
Path.relative_to("/usr/local/foo", "/")               #=> "usr/local/foo"
Path.relative_to("/usr/local/foo", "/etc")            #=> "/usr/local/foo"
Path.relative_to("/usr/local/foo", "/usr/local/foo")  #=> "."
Path.relative_to("/usr/local/../foo", "/usr/foo")     #=> "."
Path.relative_to("/usr/local/../foo/bar", "/usr/foo") #=> "bar"

If :force is set to true paths are traversed up:

Path.relative_to("/usr", "/usr/local", force: true)          #=> ".."
Path.relative_to("/usr/foo", "/usr/local", force: true)      #=> "../foo"
Path.relative_to("/usr/../foo/bar", "/etc/foo", force: true) #=> "../../foo/bar"

If a relative path is given, it is assumed to be relative to the given path, so the path is returned with "." and ".." expanded:

Path.relative_to(".", "/usr/local")          #=> "."
Path.relative_to("foo", "/usr/local")        #=> "foo"
Path.relative_to("foo/../bar", "/usr/local") #=> "bar"
Path.relative_to("foo/..", "/usr/local")     #=> "."
Path.relative_to("../foo", "/usr/local")     #=> "../foo"

Convenience to get the path relative to the current working directory.

If, for some reason, the current working directory cannot be retrieved, this function returns the given path.

Check relative_to/3 for the supported options.

Returns the path with the extension stripped.

Examples

iex> Path.rootname("/foo/bar")
"/foo/bar"

iex> Path.rootname("/foo/bar.ex")
"/foo/bar"

@spec rootname(t(), t()) :: binary()

Returns the path with the extension stripped.

This function should be used to remove a specific extension which may or may not be there.

Examples

iex> Path.rootname("/foo/bar.erl", ".erl")
"/foo/bar"

iex> Path.rootname("/foo/bar.erl", ".ex")
"/foo/bar.erl"

@spec safe_relative(t(), t()) :: {:ok, binary()} | :error

Returns a relative path that is protected from directory-traversal attacks.

The given relative path is sanitized by eliminating .. and . components.

This function checks that, after expanding those components, the path is still "safe". Paths are considered unsafe if either of these is true:

Examples

iex> Path.safe_relative("foo")
{:ok, "foo"}

iex> Path.safe_relative("deps/my_dep/app.beam")
{:ok, "deps/my_dep/app.beam"}

iex> Path.safe_relative("deps/my_dep/./build/../app.beam", File.cwd!())
{:ok, "deps/my_dep/app.beam"}

iex> Path.safe_relative("my_dep/../..")
:error

iex> Path.safe_relative("/usr/local", File.cwd!())
:error

This function is deprecated. Use safe_relative/2 instead.

@spec safe_relative_to(t(), t()) :: {:ok, binary()} | :error

Returns a relative path that is protected from directory-traversal attacks.

See safe_relative/2 for a non-deprecated version of this API.

Splits the path into a list at the path separator.

If an empty string is given, returns an empty list.

On Windows, path is split on both "\" and "/" separators and the driver letter, if there is one, is always returned in lowercase.

Examples

iex> Path.split("")
[]

iex> Path.split("foo")
["foo"]

iex> Path.split("/foo/bar")
["/", "foo", "bar"]

@spec type(t()) :: :absolute | :relative | :volumerelative

Returns the path type.

Examples

Unix-like operating systems

Path.type("/")                #=> :absolute
Path.type("/usr/local/bin")   #=> :absolute
Path.type("usr/local/bin")    #=> :relative
Path.type("../usr/local/bin") #=> :relative
Path.type("~/file")           #=> :relative

Windows

Path.type("D:/usr/local/bin") #=> :absolute
Path.type("usr/local/bin")    #=> :relative
Path.type("D:bar.ex")         #=> :volumerelative
Path.type("/bar/foo.ex")      #=> :volumerelative

Traverses paths according to the given glob expression and returns a list of matches.

The wildcard looks like an ordinary path, except that the following "wildcard characters" are interpreted in a special way:

Other characters represent themselves. Only paths that have exactly the same character in the same position will match. Note that matching is case-sensitive: "a" will not match "A".

Directory separators must always be written as /, even on Windows. You may call Path.expand/1 to normalize the path before invoking this function.

A character preceded by \\ loses its special meaning. Note that \\ must be written as \\\\ in a string literal. For example, "\\\\?*" will match any filename starting with ?..

By default, the patterns * and ? do not match files starting with a dot .. See the :match_dot option in the "Options" section below.

Options

Examples

Imagine you have a directory called projects with three Elixir projects inside of it: elixir, ex_doc, and plug. You can find all .beam files inside the ebin directory of each project as follows:

Path.wildcard("projects/*/ebin/**/*.beam")

If you want to search for both .beam and .app files, you could do:

Path.wildcard("projects/*/ebin/**/*.{beam,app}")