Help with polybar custom script module

I’m very new to NixOS and am having a hard time with some basics.

I have configured polybar using home-manager and it is working fine with the internal modules, but if I try to use external custom/scripts, I get errors.

For instance, I have a bash script for displaying the weather. If I try to point to it from the exec = statement in the module definition in home.nix, I get an error in polybar that says

/usr/bin/env: 'bash': No such file or directory

I thought I did the proper thing of changing the shebang to #!/usr/bin/env bash, but that didn’t seem to work. My script also uses curl, so I assume once I solve the bash issue, curl will be my next issue.

#!/usr/bin/env bash still requires you to explicitly have bash on your PATH for it to be found.

Generally people use helpers like writeScriptBin to create small scripts, which will give you a #!/nix/store/.../bin/sh

My example polybar script: https://github.com/jonringer/nixpkgs-config/blob/a0f7694412e269c1c26db91a1c4cda87e3242a53/nix/polybar.nix

Thanks for the reply. I’m sorry, but I am still a bit in the dark. Does that go in configuration.nix or home.nix?

Also, related question, I am trying to run the odd one-liner script from home.nix, and it looks like I need to provide the whole path, but I don’t know how to figure that out. As an example I am trying to run sed. How can I find which package sed belongs to?

If you’re on NixOS:

$ command-not-found sed
The program 'sed' is not in your PATH. It is provided by several packages.
You can make it available in an ephemeral shell by typing one of the following:
  nix-shell -p busybox
  nix-shell -p gnused
  nix-shell -p gnused_422
  nix-shell -p toybox

Not sure I understand.

I am on NixOS. sed is available at the command line. I can run it fine from there. When I try to run it in a script, it complains that it can’t find it. I assume it’s because of how the path is not available from within scripts. Need to learn more about that. I know that if I want to run it in a script I must provide the whole path like ${pkgs.package-containing-sed}/bin/sed, but how do I determine which package contains sed?

Like I said above, you can do command-not-found <command> to find the package. The NixOS channels export a database of all the executables which were built.

$ command-not-found sed
The program 'sed' is not in your PATH. It is provided by several packages.
You can make it available in an ephemeral shell by typing one of the following:
  nix-shell -p busybox
  nix-shell -p gnused
  nix-shell -p gnused_422
  nix-shell -p toybox

So in this example, gnused is likely the package that I want, as most sed usage on linux is assumed to be from the GNU sed utility.

I assume it’s because of how the path is not available from within scripts. Need to learn more about that.

Polybar (at least the home-manager module) will be ran as a systemd user service. Which means it doesn’t share anything your environment on NixOS (most systems, they will still peak into the FHS directories. To enable the script to use the command, you either need to nixify each command you call. Or you can just export a PATH at the top of the file, like I did in the example above.

1 Like

Like I said above, you can do command-not-found to find the package. The NixOS channels export a database of all the executables which were built.

Haha. Oops. I didn’t realize that was a command. I thought you were showing me an error message.

So I tried that and got an error:

DBI connect('dbname=/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite','',...) failed: unable to open database file at /run/current-system/sw/bin/command-not-found line 13.
cannot open database `/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite' at /run/current-system/sw/bin/command-not-found line 13.

Also, I am interested in doing this:
To enable the script to use the command, you either need to nixify each command you call

I am still unsure about how/where to do this. configuration.nix? I assume your example is of nixifying your pipewire.sh script, which I assume creates a nix package, puts it in the store, and makes it available “places”. Not sure how it’s path gets exported. Am I close?

Lastly, in your pipewire.sh example, I notice that you repeat your PATH export, once at the top of the file:
{ lib, coreutils, gnused, pulseaudio, pipewire, writeShellScript }:

and once within writeShellScript:
PATH=${lib.makeBinPath [ coreutils gnused pulseaudio pipewire ]}

I think I understand the second one. Those are packages required to run your script. But what about the first one?

Sorry for all the questions, and thanks for your patience. They aren’t lying when they say NixOS has a bit of a steep learning curve!

Likely, your root user is not following a nixos-* channel, as the command db isn’t available.

Another option would be to to use nix-index, which will allow you to find already installed packages with the nix-locate command.

$ nix-index
.... # create index
$ nix-locate bin/sed --type x
(zulip.out)                                     217,240 x /nix/store/p1x8lgsv6b2g41gy13cvildl92ff09z7-gnused-4.8/bin/sed
(steam-run-native.out)                          202,320 x /nix/store/dhcjqsvr0kynlx39mpfqagkydgclcdlf-bootstrap-tools/bin/sed
sloccount.out                                       269 x /nix/store/vvqqx2ycaykx87v6adnabalhf0224njm-sloccount-2.26/bin/sed_count
setools.out                                         424 x /nix/store/x6m3hr96h1n6x7r03a5lcb6l1x3cpqnr-setools-4.3.0/bin/sediff
setools.out                                         423 x /nix/store/x6m3hr96h1n6x7r03a5lcb6l1x3cpqnr-setools-4.3.0/bin/sedta
sedutil.out                                     513,616 x /nix/store/akvak4j887542i114nb2w6ahcwv71rkq-sedutil-1.15.1/bin/sedutil-cli
plan9port.out                                   465,672 x /nix/store/61751pix0b7vrg9zysx5hx917hasy34m-plan9port-2021-04-22/plan9/bin/sed
(libidn2.bin)                                   190,872 x /nix/store/p4s4jf7aq6v6z9iazll1aiqwb34aqxq9-bootstrap-tools/bin/sed
gnused.out                                      207,664 x /nix/store/klwhsp6f58mqkil6aq59zcj4k7zgcqix-gnused-4.8/bin/sed
gnused_422.out                                   90,808 x /nix/store/g694yj8clr77v2n3bcg824cvm4fllbh2-gnused-4.2.2/bin/sed

OK, I’m trying…

I followed your example and created weather.nix for my script with writeShellScript. I called the script "weather.sh" from within weather.nix. I put weather.nix in .config/nixpkgs next to home.nix. I added imports = [ ./weather.nix ]; to home.nix. I call weather.sh directly, with no path, from within my polybar config.

When I run home-manager switch, I get the following error:

error: anonymous function at /home/user/.config/nixpkgs/weather.nix:1:1 called with unexpected argument 'config', at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:372:8
(use '--show-trace' to show detailed location information)

Am I close?

Hmm, I think you should start with the basics. I have a kind of “intro to nix” video here: https://www.youtube.com/watch?v=LiEqN8r-BRw

If you prefer written format: Nix Pills | Nix & NixOS

OK. I have gone through your config files, and I think I partially understand what you are doing.

First, I don’t understand this:

  home.file.".config/polybar/pipewire.sh" = {
    source = pkgs.polybar-pipewire;
    executable = true;

This looks like a statement that creates “pipewire.sh”, which you call from your polybar config. But what is “pkgs.polybar-pipewire”? Where did that come from? I would guess that it is created from your “pipewire.nix”, but “pipewire.nix” references “pipewire.sh” internally, and nowhere do I see how the package would receive the name “pkgs.polybar-pipewire”.