通过 shebang 在 nix 中设置环境变量

Setting environment variables in nix via a shebang

是否可以在使用通过 shebang 调用的 nix-shell 时设置环境变量?例如,我正在使用

#! /usr/bin/env nix-shell
#! nix-shell -i runghc --pure

并想设置一个环境变量,如 FOO=bar。注意,FOO不一定是由周围环境定义的。因此 --keep FOO 不是一个选项。

您似乎在使用随附的 shell.nix 文件。您可以简单地将环境变量定义为那里的派生属性。

shell.nix

pkgs.mkShell {
  buildInputs = [ pkgs.ghc ];
  shellHook = ''
    VIA_SHELL_HOOK=it\ works   # no it doesn't
  '';
  VIA_DRV_ATTR = "working";
}

示例可执行脚本

#!/usr/bin/env nix-shell
#!nix-shell -i runghc --pure

import System.Environment(getEnv)

main = do
  getEnv "VIA_DRV_ATTR" >>= print
  getEnv "VIA_SHELL_HOOK" >>= print

输出:

"working"
hello: VIA_SHELL_HOOK: getEnv: does not exist (no environment variable)

(Nix 2.3.4,Nixpkgs 20.03)

是的,在使用带有 shebang 的 nix 时可以设置环境变量。

nix 作为单个文件中的主要语言 bash shebang

#! /usr/bin/env -S bash -c 'nix-shell --pure [=10=]'

with import <nixpkgs> {};
let
  haskellCode = ''
    import System.Environment (getEnv)

    main = do
      getEnv "VIA_DRV_ATTR" >>= print
      getEnv "VIA_SHELL_HOOK" >>= print
  '';
in
mkShell {
  buildInputs = [ ghc ];
  shellHook = ''
    export VIA_SHELL_HOOK="VIA_SHELL_HOOK works"
    exec runghc <<< '${haskellCode}'
  '';
  VIA_DRV_ATTR = "VIA_DRV_ATTR works";
}
$ ./test.nix 
"VIA_DRV_ATTR works"
"VIA_SHELL_HOOK works

缺点是 haskell 代码会嵌入到 nix 字符串中。

haskell(或任何其他)作为带有 nix shebang

的单个文件中的主要语言
#! /usr/bin/env nix-shell
#! nix-shell -i runghc --pure -E "with import <nixpkgs> {}; mkShell { buildInputs = [ ghc ]; VIA_DRV_ATTR = \"VIA_DRV_ATTR works\"; shellHook = ''export VIA_SHELL_HOOK=\"VIA_SHELL_HOOK works\"''; }"

import System.Environment (getEnv)

main = do
  getEnv "VIA_DRV_ATTR" >>= print
  getEnv "VIA_SHELL_HOOK" >>= print
$ ./test.hs
"VIA_DRV_ATTR works"
"VIA_SHELL_HOOK works"

缺点是冗长的 shebang nix-shell 行带有转义引号。似乎没有办法将它分成几行。

使用 shebang 在一个文件中同时使用 nix 和另一种语言?

也许可以将2个语言块一个接一个地组合起来,然后按照combining bash and haskell.

的方式在shebang行中编写一些生成器脚本