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.)

bdesham
  • 1,307
  • 2
  • 13
  • 23

2 Answers2

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.

  • 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 06 '19 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. – Gilles 'SO- stop being evil' Sep 06 '19 at 20:56
  • Oh, even better. Thanks for clarifying. – bdesham Sep 06 '19 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 '21 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. – Gilles 'SO- stop being evil' Mar 12 '21 at 17:34
  • @Gilles'SO-stopbeingevil' - overriding PATH is indeed the culprit then it seems... though I'd have though that this is fairly standard practice meaning your answer is only useful in limited scenarios. Or have I been overriding PATH in the wrong place..? – jmetz Mar 12 '21 at 17:49
  • Regardless, I'd suggest adding an emphasized note to your answer highlighting the PATH issue, as I doubt I'd be the only person left scratching my head after trying your answer. – jmetz Mar 12 '21 at 17:54
  • @jmetz No, setting environment variables in .zshrc or .bashrc is bad practice, in part because it breaks per-session environments as you noticed. – Gilles 'SO- stop being evil' Mar 12 '21 at 18:38
  • @jmetz I don't really see what to add to my answer. Your problem has nothing to do with this question: it's independent of the shell, whereas the question is about using a sh script with zsh. – Gilles 'SO- stop being evil' Mar 12 '21 at 18:39
  • @Gilles'SO-stopbeingevil' Have you tried googling "setting PATH zsh"? Pretty much every result suggests setting PATH in .zshrc, so bad practice or no, your answer needs to take the fact that there are probably many zshrcs with PATH setting in them. – jmetz Mar 13 '21 at 12:47
  • @jmetz In my experience this bad recommendation almost always mentions .bashrc and is partly due to the bizarre treatment of shrc files by bash. But ok, I've added a warning not to do this. Maybe the bad practice has migrated to zsh with macOS? – Gilles 'SO- stop being evil' Mar 13 '21 at 13:06
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.

Feline
  • 138
  • 5
bdesham
  • 1,307
  • 2
  • 13
  • 23