Skip to content

Instantly share code, notes, and snippets.

@CMCDragonkai
Last active March 15, 2024 00:21
Show Gist options
  • Star 52 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save CMCDragonkai/de84aece83f8521d087416fa21e34df4 to your computer and use it in GitHub Desktop.
Save CMCDragonkai/de84aece83f8521d087416fa21e34df4 to your computer and use it in GitHub Desktop.
Nix: String and Path Concatenation #nix #nixos

Nix String and Path Concatenation

From Bas van Dijk:

To understand these things I would recommend using nix-repl:

$ nix-repl
Welcome to Nix version 1.11.2. Type :? for help.

nix-repl> name = "bar"

nix-repl> ./foo + "${name}"
/home/bas.van.dijk/foobar

Note that the previous is equivalent to the simpler:

nix-repl> ./foo + name
/home/bas.van.dijk/foobar

The reason that you get "foobar" is that we didn't include a "/". So lets try to do that:

nix-repl> ./foo/ + name
error: syntax error, unexpected '+', at (string):1:8

Apparently the Nix path parser doesn't like a slash at the end of a path literal. So lets try adding the slash dynamically:

nix-repl> ./foo + "/" + name
/home/bas.van.dijk/foobar

What happened here? Well, + is left associative so it is interpreted as:

(./foo + "/") + name

Lets try evaluating that left expression alone:

nix-repl> ./foo + "/"
/home/bas.van.dijk/foo

Apparently Nix performs normalization on paths since the final slash is not included. So lets put the parenthesis differently:

nix-repl> ./foo + ("/" + name)
/home/bas.van.dijk/foo/bar

That's better! Now we can shorten this using some antiquotation:

nix-repl> ./foo + "/${name}"
/home/bas.van.dijk/foo/bar

Note that if you use import pkgs.path the path type of pkgs.path means that the contents will not be stored in /nix/store. However if you use import "${pkgs.path}", the pkgs.path gets interpolated as a string, and the pkgs.path then imported into the /nix/store. The former is more efficient than the latter. Remember you can always convert a path to a string with builtins.toString, but to do it other way you can use instead ./. + "string" or /. + "string".

@jeremyschlatter
Copy link

You saved me some time today. Thank you!

@YuMingLiao
Copy link

Great intro. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment