Search code examples
pythonvirtualenvwindows-subsystem-for-linuxnixnixos

Writing One Shell script to first enter nix shell, then enter the python virtual environment


I want to schedule a job from wsl. The job will need to be run in the nix-shell and then in the python virtual environment under Nix-shell. I try to do this by writing a shell script, run ./enter.sh.

#!/bin/bash
nix-shell -p python38Full python38Packages.virtualenv;
source .venv/bin/activate

However, it doesn't enter the

(virt)
[nix-shell:xxx] 

after I run ./enter.sh. I need to first run the first line, then run the second line separately. It would be super helpful if someone knows a way to write a shell script that can do these two steps by running one script.


Solution

  • Shell scripts are a bit different from interactive sessions in the terminal.

    When you run nix-shell in your terminal, the original shell process creates a nix-shell process and lets it read your input until nix-shell exits, returning control to the original shell.

    In a shell script on the other hand, the shell will read all lines by itself and will not delegate the processing of the shell script to other executables like nix-shell. *

    If you want to run all commands in the nix-shell, you can use a special shebang at the top of the file. For example:

    #!/usr/bin/env nix-shell
    #!nix-shell -p python38Full -p python38Packages.virtualenv
    #!nix-shell -i bash
    source .venv/bin/activate
    
    # insert commands to be run here
    
    

    /usr/bin/env is just a helper to look up nix-shell without an absolute path. nix-shell is run as a script interpreter that will parse #!nix-shell lines for its own options. The -i bash option tells it to invoke bash as the actual interpreter for this script. bash ignores the shebang and #!nix-shell lines, because they're comments. nix-shell has set the right environment variables in advance. It continues to source the activate file.

    You might want to generate the activate script before running source, but I suppose that depends on your workflow.

    Alternatively, you could use the --run COMMAND option of nix-shell to run single commands in the context provided by Nix.


    *: commands in parentheses do run in a separate process, but this is mostly an implementation detail. It won't let other programs take over the execution of the script.