1

I made a very simple fish shell script to activate an specific python virtual environment.

If I execute the source command manually in the fish shell everything works fine but running it with the following shell script does not activate the venv.

#! /usr/bin/fish
set FILEPATH "/home/shyney/.venv/venvname/bin/activate.fish"
if test -e $FILEPATH
  source $FILEPATH
  echo "activation file found"
  echo $FILEPATH
end

The script runs fine but the venv is still not activated.

shyney
  • 67
  • 11
  • Sure it does. Why would you say that it doesn't? – thebjorn Sep 16 '21 at 12:18
  • 1
    Not really a duplicate of the question that was linked by a mod. The title of the "marked dup" might make someone *think* it has the answer, but it's really a very different question/scenario. [Here](https://stackoverflow.com/q/16011245/11810933) is a better duplicate, which covers this question, IMHO. – NotTheDr01ds Sep 16 '21 at 17:30
  • 1
    But ultimately, IMHO, not a duplicate at all that I can tell (but I'm still a few rep shy of being able to cast votes in this area), since this is about the Fish shell and there are different answers that apply (albeit the same root cause as in the question I linked). – NotTheDr01ds Sep 16 '21 at 18:08

1 Answers1

2

Short-answer proposal:

alias -s myvenv="source /home/shyney/.venv/venvname/bin/activate.fish"

Replace myenv with whatever you want to call your venv activation function/alias. Then just call myenv to activate, and (as usual) deactivate to end the venv.

The alias -s command only needs to be run one time, since it saves the function in ~/.config/fish/functions/myvenv.fish (by default). The function is "lazy-loaded" (because the function is named the same as the file in the functions dir) when you call myvenv for the first time in a shell.


Explanation:

Sort of a a duplicate of this Bash question, at least at the "root cause", but since this question is about Fish, there's ultimately a different/better answer.

I think most of us run across this at some point early in our "shell/command-line" experience.

The reason you can't source a file inside a script is the same reason that you have to source it in the first place (otherwise, Python would have just made it an executable).

The difference between executing a script vs. sourcing:

  • When you run a script, the script runs in its own process (typically a "subshell") which has its own environment. When the script exits, the parent process returns, with its (unchanged) environment. So the venv is active within the script, albeit very briefly. When the script concludes, the venv environment is no longer present in your interactive shell.

  • When you source a file, on the other hand, the commands in the file are read into the current shell process. That's why sourcing can change the current shell's environment.

My recommended workaround for your use-case, is to create this as a function, rather than an executable script. A Fish function (and for most shells) does run in the current shell process and can modify the global environment.

There are several ways to do this. The easiest is to use the alias command as above. As explained there, this creates a function declaration in a lazy-loaded file. The function isn't loaded into memory until you need it. This is a feature found in Fish and Zsh, but not Bash or Posix. But ultimately it's more user-friendly (IMHO) in Fish.

Defining it as an alias also allows you to easily recall it with the alias command. For example:

> alias
alias exa 'exa -l --color=always --header --icons -F $argv | bat'
alias ls 'exa -l --color=always --header --icons -F $argv | bat'
alias myvenv 'source /home/shyney/.venv/venvname/bin/activate.fish'

But there's also nothing that prevents you from doing this manually, without the Fish syntactic-sugar of the alias. Just create a file ~/.config/fish/functions/myvenv.fish with the following:

function myvenv
    source "/home/shyney/.venv/venvname/bin/activate.fish"
end

As long as the function name and the filename match, it will work.

NotTheDr01ds
  • 15,620
  • 5
  • 44
  • 70
  • Thank you. This is just my second shell script so I didn't know this and also couln't find anything. So there is no way to simplify the command other than sourcing it with the full path in the current shell process... – shyney Sep 16 '21 at 13:11
  • 1
    @shyney On mobile, but just edited the answer with a possible workaround. I'll add the detail in about an hour. – NotTheDr01ds Sep 16 '21 at 13:26
  • 1
    @shyney Well, one errand turned into another so it was 4 hours on the road rather than just 1 ;-), but let me know if the `alias`/`function` option works out for you. – NotTheDr01ds Sep 16 '21 at 18:03
  • Thank you so much for your detailed answer! This helps me a lot to understand more about shells and fish. I also dont think that this is a duplicate but it seems that I cant change it without creating a new question... – shyney Sep 20 '21 at 09:13