2

I have a script at /venv/bin/activate that sets some environment variables. I’m looking for a way to start zsh, have it source this script, and then continue with a normal interactive session. When I exit this session, the session I return to should not know about any of the environment changes that activate made. How can I invoke zsh like this?

(This is pretty much the same question as this one, except that I’m using zsh instead of bash.)

2
  • 1
    Similar: Start zsh with a custom zshrc. My answer there will give you some approaches. Sep 7, 2019 at 14:10
  • Since asking this question I’ve started using direnv, which is a tool that integrates with zsh, bash, and others to set “per-directory environment variables” in a way that is very close to what I was asking for here.
    – bdesham
    Dec 18, 2023 at 2:12

2 Answers 2

2

If the activate script only sets environment variables, you can read it in one shell, then execute a new, interactive zsh instance.

sh -c '. /venv/bin/activate; exec zsh -i'

The wrapper shell sh can be replaced by any shell that is able to parse /venv/bin/activate, including zsh if the activate script is compatible with it.

In addition to environment variables, the interactive zsh instance will inherit the process ID and a few other process settings such as resource limits (ulimit …) and ignored signals (trap '' …). On the other hand, settings of the shell itself are not preserved: shell variables (var=… if var is not exported), shell options (set -… or shopt …), key bindings, alias and function definitions, etc.

Obviously this won't work if your .zshrc overrides environment variables set by the activate script. That's one of the reasons .*shrc files should not set environment variables.

12
  • This is a good solution as long as you don’t need to return to the original shell afterward (and as long as the effects of activate fall into only the categories you mentioned).
    – bdesham
    Sep 6, 2019 at 20:45
  • @bdesham Yes, I meant that you should run that as a separate shell script but I can see that it isn't clear, I'll clarify. Sep 6, 2019 at 20:56
  • Oh, even better. Thanks for clarifying.
    – bdesham
    Sep 6, 2019 at 21:40
  • This doesn't work with modern zsh (nb it works if the final shell command is sh or bash, for example)
    – jmetz
    Mar 12, 2021 at 16:17
  • @jmetz What doesn't work? It certainly works with Python virtual environments, and I don't see what recent changes in zsh could break similar scripts from other communities. The only thing I can see that would break it is if you do something weird in your .zshrc like overriding PATH. In which case, don't do this. Mar 12, 2021 at 17:34
1

Using ZDOTDIR

Create a (possibly temporary) directory at, say, ~/venv_startup that contains two files, .zshenv and .zshrc. The .zshenv file consists of

source ~/.zshenv
source /venv/bin/activate

while .zshrc says

source ~/.zshrc

Now, invoke zsh via

zsh -c "ZDOTDIR=~/venv_startup zsh"

This says to zsh, “instead of starting out by sourcing the .zshenv and .zshrc files in $HOME, source the files of those names in /venv_startup instead.” Since the versions in /venv_startup source the ones in $HOME anyway, the net effect is that the shell will run

source /venv/bin/activate

in between executing your zshenv and your zshrc. After that, it will be a normal interactive session.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .