In a previous Nix post I mentioned how you can run once-off commands with Nix without polluting your system environment.
In this post, I want to demonstrate how you can create self-contained and reproducible scripts using the Nix shebang.
Simple cowsay script
Using the interactive nix-shell
To start, imagine a scenario where you want a cow to “moo” using cowsay.
The bash script moo.sh
would contain.
#!/usr/bin/env bash
cowsay "moo"
To obtain the cowsay binary without polluting your system environment you would first generate a temporary environment.
nix-shell -p cowsay
And then execute the script.
./moo.sh
Using the nix-shell
shebang
A cleaner, more contained, approach would be to use the nix-shell
shebang.
The moo.sh
script would then look like.
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p cowsay
cowsay "moo"
The first line should always be #!/usr/bin/env nix-shell
.
The second line describes the script language (in this case bash) and the dependencies (cowsay).
Executing the script is then just as simple as executing any executable.
./moo.sh
Using “pure” environments
The above example doesn’t strictly check if cowsay
was declared in the dependencies. To enforce this check,
i.e. all dependencies used in the script HAS to be declared on line 2, you need to use the --pure
arg.
#!/usr/bin/env nix-shell
#!nix-shell --pure -i bash -p cowsay
cowsay "moo"
A real world example using my dot
binary
I was able to simplify my dotfiles by replacing my shell.nix
with a shebang declaration. See the
diff.
Conclusion
The Nix shebang provides a cleaner, self-contained and reproducible (if you use the --pure
arg) method of writing scripts.