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.
CodePudding user response:
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.