Nix-shell shebang: Difference between revisions
imported>Milahu add links: Speeding up nix-shell shebang, cached-nix-shell |
|||
(11 intermediate revisions by 9 users not shown) | |||
Line 7: | Line 7: | ||
The first shebang line is always <code>#! /usr/bin/env nix-shell</code>.<br> | The first shebang line is always <code>#! /usr/bin/env nix-shell</code>.<br> | ||
The second shebang line declares the script language and the script dependencies. | The second shebang line declares the script language and the script dependencies. | ||
As of Nix 2.19.0 you can also use the new CLI <code>nix shell</code> and flakes to define shebangs. See [https://nixos.org/manual/nix/stable/command-ref/new-cli/nix.html?highlight=shebang#shebang-interpreter docs]. | |||
== Examples == | == Examples == | ||
Line 16: | Line 18: | ||
<syntaxHighlight lang="bash"> | <syntaxHighlight lang="bash"> | ||
#! /usr/bin/env nix-shell | #! /usr/bin/env nix-shell | ||
#! nix-shell -i bash | #! nix-shell -i bash -p bash | ||
echo hello world | echo hello world | ||
Line 36: | Line 38: | ||
<syntaxHighlight lang="python"> | <syntaxHighlight lang="python"> | ||
#! /usr/bin/env nix-shell | #! /usr/bin/env nix-shell | ||
#! nix-shell -i python3 | #! nix-shell -i python3 -p python3 | ||
print("hello world") | print("hello world") | ||
Line 54: | Line 56: | ||
image.save(path) | image.save(path) | ||
print(ansicolor.green(f"done {path}")) | print(ansicolor.green(f"done {path}")) | ||
</syntaxHighlight> | |||
=== Rust === | |||
==== No dependencies ==== | |||
<syntaxHighlight lang="bash"> | |||
#!/usr/bin/env nix-shell | |||
#![allow()] /* | |||
#!nix-shell -i bash -p rustc | |||
rsfile="$(readlink -f $0)" | |||
binfile="/tmp/$(basename "$rsfile").bin" | |||
rustc "$rsfile" -o "$binfile" --edition=2021 && exec "$binfile" $@ || exit $? | |||
*/ | |||
fn main() { | |||
for argument in std::env::args().skip(1) { | |||
println!("{}", argument); | |||
}; | |||
println!("{}", std::env::var("HOME").expect("")); | |||
} | |||
</syntaxHighlight> | |||
==== With dependencies ==== | |||
uses [https://github.com/fornwall/rust-script rust-script] | |||
<syntaxHighlight lang="bash"> | |||
#!/usr/bin/env nix-shell | |||
//! ```cargo | |||
//! [dependencies] | |||
//! time = "0.1.25" | |||
//! ``` | |||
/* | |||
#!nix-shell -i rust-script -p rustc -p rust-script -p cargo | |||
*/ | |||
fn main() { | |||
for argument in std::env::args().skip(1) { | |||
println!("{}", argument); | |||
}; | |||
println!("{}", std::env::var("HOME").expect("")); | |||
println!("{}", time::now().rfc822z()); | |||
} | |||
</syntaxHighlight> | |||
=== Haskell === | |||
<syntaxHighlight lang="haskell"> | |||
#! /usr/bin/env nix-shell | |||
#! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [turtle])" -i runghc | |||
{-# LANGUAGE OverloadedStrings #-} | |||
import Turtle | |||
main = echo "Hello world!" | |||
</syntaxHighlight> | </syntaxHighlight> | ||
Line 63: | Line 119: | ||
#! /usr/bin/env nix-shell | #! /usr/bin/env nix-shell | ||
#! nix-shell -i bash | #! nix-shell -i bash | ||
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs | #! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/aed4b19d312525ae7ca9bceb4e1efe3357d0e2eb.tar.gz | ||
echo hello world | echo hello world | ||
</syntaxHighlight> | </syntaxHighlight> | ||
== Flake == | |||
It is also possible to make it work for flake like in: | |||
<syntaxHighlight lang="bash"> | |||
#!/usr/bin/env -S nix shell nixpkgs#bash nixpkgs#hello nixpkgs#cowsay --command bash | |||
hello | cowsay | |||
</syntaxHighlight> | |||
The [https://nix.dev/manual/nix/2.19/command-ref/new-cli/nix3-shell doc] mentions that it should be possible to run more complex commands using multiple lines, but it does not work for me as reported [https://github.com/NixOS/nixpkgs/issues/280033 here]. | |||
== Performance == | |||
TODO ... why the startup delay? how to make it faster? | |||
* [https://discourse.nixos.org/t/speeding-up-nix-shell-shebang/4048 Speeding up nix-shell shebang] | |||
* [https://github.com/xzfc/cached-nix-shell cached-nix-shell] - Instant startup time for nix-shell | |||
* [https://www.tweag.io/blog/2020-06-25-eval-cache/ Nix Flakes, Part 2: Evaluation caching - Tweag] | |||
== See also == | == See also == | ||
Line 74: | Line 150: | ||
* [https://gist.github.com/travisbhartwell/f972aab227306edfcfea nix-shell and Shebang Lines] | * [https://gist.github.com/travisbhartwell/f972aab227306edfcfea nix-shell and Shebang Lines] | ||
* [https://notes.yukiisbo.red/posts/2021/07/Spice_up_with_Nix_Scripts.html Spice up with Nix: Scripts with magical dependencies] | * [https://notes.yukiisbo.red/posts/2021/07/Spice_up_with_Nix_Scripts.html Spice up with Nix: Scripts with magical dependencies] | ||
[[Category:Nix]] | |||
[[Category:Shell]] |
Latest revision as of 21:58, 28 May 2024
You can use nix-shell
as a script interpreter to
- run scripts in arbitrary languages
- provide dependencies with Nix
To do this, start the script with multiple shebang (#!
) lines.
The first shebang line is always #! /usr/bin/env nix-shell
.
The second shebang line declares the script language and the script dependencies.
As of Nix 2.19.0 you can also use the new CLI nix shell
and flakes to define shebangs. See docs.
Examples
Bash
To run bash scripts, set the interpreter with -i bash
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p bash
echo hello world
You can use nix-shell -p ...
to add dependencies:
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p imagemagick cowsay
# scale image by 50%
convert "$1" -scale 50% "$1.s50.jpg" &&
cowsay "done $1.q50.jpg"
Python
#! /usr/bin/env nix-shell
#! nix-shell -i python3 -p python3
print("hello world")
#! /usr/bin/env nix-shell
#! nix-shell -i python3 -p python3Packages.pillow python3Packages.ansicolor
# scale image by 50%
import sys, PIL.Image, ansicolor
path = sys.argv[1]
image = PIL.Image.open(path)
factor = 0.5
image = image.resize((round(image.width * factor), round(image.height * factor)))
path = path + ".s50.jpg"
image.save(path)
print(ansicolor.green(f"done {path}"))
Rust
No dependencies
#!/usr/bin/env nix-shell
#![allow()] /*
#!nix-shell -i bash -p rustc
rsfile="$(readlink -f $0)"
binfile="/tmp/$(basename "$rsfile").bin"
rustc "$rsfile" -o "$binfile" --edition=2021 && exec "$binfile" $@ || exit $?
*/
fn main() {
for argument in std::env::args().skip(1) {
println!("{}", argument);
};
println!("{}", std::env::var("HOME").expect(""));
}
With dependencies
uses rust-script
#!/usr/bin/env nix-shell
//! ```cargo
//! [dependencies]
//! time = "0.1.25"
//! ```
/*
#!nix-shell -i rust-script -p rustc -p rust-script -p cargo
*/
fn main() {
for argument in std::env::args().skip(1) {
println!("{}", argument);
};
println!("{}", std::env::var("HOME").expect(""));
println!("{}", time::now().rfc822z());
}
Haskell
#! /usr/bin/env nix-shell
#! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [turtle])" -i runghc
{-# LANGUAGE OverloadedStrings #-}
import Turtle
main = echo "Hello world!"
Pinning nixpkgs
To pin nixpkgs to a specific version, add a third shebang line:
#! /usr/bin/env nix-shell
#! nix-shell -i bash
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/aed4b19d312525ae7ca9bceb4e1efe3357d0e2eb.tar.gz
echo hello world
Flake
It is also possible to make it work for flake like in:
#!/usr/bin/env -S nix shell nixpkgs#bash nixpkgs#hello nixpkgs#cowsay --command bash
hello | cowsay
The doc mentions that it should be possible to run more complex commands using multiple lines, but it does not work for me as reported here.
Performance
TODO ... why the startup delay? how to make it faster?
- Speeding up nix-shell shebang
- cached-nix-shell - Instant startup time for nix-shell
- Nix Flakes, Part 2: Evaluation caching - Tweag