1

interactive programs can typically read input from stdin, e.g.,

$ echo echo hello | bash
hello

or

$ echo 1 2 + p | dc
3

however, nix-shell does not seem to behave this way, e.g.

$ echo hello | nix-shell -p  hello
$

whereas the expected output would have been Hello, world!.

using the trick suggested in nix-shell(1):

       --command cmd
           In the environment of the derivation, run the shell command cmd. This command is executed in an
           interactive shell. (Use --run to use a non-interactive shell instead.) However, a call to exit is
           implicitly added to the command, so the shell will exit after running the command. To prevent
           this, add return at the end; e.g.  --command "echo Hello; return" will print Hello and then drop
           you into the interactive shell. This can be useful for doing any additional initialisation.

leads to an error:

$ echo hello | nix-shell -p  hello --command return
/tmp/nix-shell-15399-0/rc: line 1: return: can only `return' from a function or sourced script
$

my versions of the relevant programs are these:

$ nix --version
nix (Nix) 2.3.2
$ bash --version
GNU bash, version 4.4.23(1)-release (x86_64-pc-linux-gnu)
$ 

hence my question: how do i make nix-shell read from stdin, like bash or dc?

1 Answers1

3

Unlike its name may suggest, nix-shell isn't a shell in the typical UNIX sense of the word; only in the broader sense that it's a program for starting programs.

The -p arguments only serve to bring software into the shell's environment. You can use multiple and they don't have the effect of actually running those programs*.

To make nix-shell start bash, regardless of nix-shell's own logic, use for example:

$ echo hello | nix-shell -p hello --run bash
Hello, world!
Robert Hensing
  • 6,708
  • 18
  • 23
  • thanks for your answer, but it does not solve my problem. let me clarify: i used the `-p hello` merely as a dummy. in my application i have a `shell.nix` file with a fairly involved `shellHook` script (that has internal state). this works perfectly when run interactively, i.e., i can run functions defined by the `shellHook` perfectly fine. now i need to do the same by piping commands into `nix-shell` instead of typing them manually. by general unix philosophy this should work. why doesn't it? is it because `nix-shell` tries to be too smart and guess whether it's attached to a terminal? – Björn Gohla Jul 04 '20 at 22:59
  • note in particular that the `--run bash` is no use to me, i need the pipe to feed commands into the same interpreter that executed the `shellHook`. – Björn Gohla Jul 04 '20 at 23:07
  • 2
    Try `echo hello | nix-shell -p hello --command 'source /dev/stdin'` and please use capital letters as appropriate. Considering that you're asking a favor, you don't just come across as lazy, but inconsiderate and rude. You've just made it harder for anyone to fulfill that favor. Use this advice to your advantage; no need to reply. – Robert Hensing Jul 05 '20 at 19:45
  • The `--run` seems to work now, it also uses the `shellHook` as long as it is defined in the `shell.nix`. At least I tried on an interactive terminal, and just doing `echo 'echo hello' | nix-shell --run bash` was sufficient to run the `echo hello` after the `shellHook` executed. Now if the `-p` is set, that's when `shell.nix` is not executed and that ends up being a problem. So you can't really use `-p` at the same time with `shell.nix`. – CMCDragonkai Jul 10 '22 at 06:21