Nix on non-NixOS -- path to e.g. bash when PATH is unset?

Hello,

After a year or so of halfhearted investigation, I’m finally giving a real shot to using nix, nix-darwin, and home-manager on my MacOS and Arch Linux systems (with NixOS on a VM and a Pi as well).

One issue I’ve run into a few times is adapting my current launchd / systemd / Quicksilver / Hammerspoon scripts to use nix-installed programs (e.g. bash). These are usually run without my PATH being fully configured. Previously, for example, if I wanted to use bash 5 via homebrew (instead of system-installed bash 3 on MacOS), I could just prefix PATH=/opt/homebrew/bin:${PATH}, or directly use /opt/homebrew/bin/bash myscript.sh (if no other homebrew binaries were required).

I’ve now brew unlinked bash from /opt/homebrew/bin, so all my scripts are broken for the moment.

I have nixpkgs#bashInteractive installed, so using /usr/bin/env bash as my shebang works from a login shell, but not for things getting called by launchd / root.

It looks like I have maybe a few options –

  • /run/current-system/sw/bin/bash
  • /nix/var/nix/profiles/system/sw/bin/bash

These two also look possible, though I don’t have bash there currently (just system-wide), but I’m sure it would be easy to do:

  • /nix/var/nix/profiles/per-user/n8henrie/home-manager/home-path/bin/
  • /etc/profiles/per-user/n8henrie/bin

Even if I were to change the shebang to nix-shell I would still need to specify a path to nix-shell, right?

Perhaps not:

$ which bash
/run/current-system/sw/bin/bash
$ sudo -i which bash
/bin/bash
$ sudo -i which nix-shell
/run/current-system/sw/bin/nix-shell

So perhaps nix is at least already on my PATH? So maybe I should change these paths to all use nix run nixpkgs#bash -- myscript.sh?

EDIT: systemd requires ExecStart to start with an absolute path, so just nix run won’t work – /usr/bin/env nix in that case?

The way to do it on NixOS is to write your systemd modules with nix, and use its string interpolation of packages to get the correct binary. Something like this: nixpkgs/emacs.nix at 47edaa313fc3767ce3026037a5b62352f22f3602 · NixOS/nixpkgs · GitHub

The documentation for that option is here: systemd.services

Ignore that, didn’t spot you were using home-manager. It has similar options for systemd units though, so also here I would recommend writing the services with nix and using string interpolation for the package: Appendix A. Configuration Options

I guess in theory running /usr/bin/env nix-shell might work, but I’m not at all sure what channels that command would be using. It’s definitely not reproducible, whatever the case.

My primary machine is MacOS.

Yes, I’m aware there are systemd and launchd options for home-manager, but not Quicksilver or Hammerspoon, or other applications running scripts that I’m hoping to eventually migrate to nix, but it would be nice to have a quick fix in the meantime.

Which path would you consider least bad for a service on a non-NixOS system?

  • /nix/var/nix/profiles/system/sw/bin/bash
  • /run/current-system/sw/bin/bash
  • /etc/profiles/per-user/n8henrie/bin/bash
  • /usr/bin/env nix run nixpkgs#bash

0 voters

Unfortunately it looks like PATH is only /usr/bin:/bin:/usr/sbin:/sbin in some of the environments, so unfortunately I don’t think that will be a good option.

Neither one of these quite match your case, but FWIW my /etc/shells uses the current-system path (I think nix-darwin does this):

$ cat /etc/shells
Tue Oct 18 2022 14:40:29 --> 
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh

# List of shells managed by nix.
/run/current-system/sw/bin/bash

It might also be acceptable to define the launchdaemon in Nix without fully nix-packaging the script, and then use the system path:

    launchd.user.agents.backup = {
        path = [ config.environment.systemPath ];
        command = "~/.config/persistence/backup.sh ${user.handle}";
        serviceConfig = {
            StartCalendarInterval = [
                { Hour = 7; }
                { Hour = 23;}
            ];
        };
    };

Mine has /run/current-system/sw/bin/bash there too; something in e.g. Hammerspoon must be overriding it.

IIRC it’s just a list of valid user shells, so you still have to use chsh to adopt it. Probably not a very safe idea to use a non-builtin shell as the root user’s shell, though.

I just mean it as evidence that at least one other Nixer has looked at this question and decided that hardcoding /run/current-system/sw/bin/bash is tolerable!

1 Like

Yes, I have already done so for my user as well as root.

:laughing: