Closed uvlad7 closed 10 months ago
IMHO, this instruction should be updated too.
UPD: Completions still don't work when added into .profile
:
vladimir@np940x5n:~$ shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'
Not login shell
vladimir@np940x5n:~$ complete -p | grep brew
vladimir@np940x5n:~$ . .profile
vladimir@np940x5n:~$ complete -p | grep brew
complete -o bashdefault -o default -F _brew brew
and it looks like that .bashrc
is a right place for the completions (standart /etc/bash_completion
is sourced there, for example)
Thanks for the issue @uvlad7!
CC @Homebrew/maintainers folks for thoughts and help. My experience here is that there is the "proper location" (.*profile
) and "the location that consistently works across all Linux distros and macOS versions/shells" and we should probably always do the latter.
I think ~/.bashrc
or ~/.zshrc
may be the better location to place the brew
initialization command.
~/.bash_profile
is read by bash
when it is invoked as a login shell, i.e.:
bash --login
Usually, the login shell mode can be configured by the terminal simulator. It is similar to zsh
for ~/.zprofile
over ~/.zshrc
with the --login
option. Here is the pseudo-code:
if is login shell:
if ~/.bash_profile exists; then
source ~/.bash_profile
elif ~/.profile exists; then
source ~/.profile # ~/.profile will not be read if ~/.bash_profile exists
fi
else
if ~/.bashrc exists; then
source ~/.bashrc # bash will not read ~/.bash_profile on non-login shell mode
fi
fi
In the default configuration, ~/.bash_profile
will contain a statement to source ~/.bashrc
.
# ~/.bash_profile
if [[ -f ~/.bashrc ]]; then
source ~/.bashrc
fi
So ~/.bashrc
will always be sourced for both login shell and non-login shell cases.
I think
~/.bashrc
or~/.zshrc
may be the better location to place thebrew
initialization command.
@XuehaiPan Agreed. Could you open a PR for this to Homebrew/install and Homebrew/brew? 🙇🏻
Opened a PR to resolve this.
@XuehaiPan, but profile files are sourced only once, just a little performance optimization. And guidelines say that .*profile
files are the place to configure things like PATH
variable. It's not true about completions, they don't work in subshells, so they should be configured in rcfiles.
I've added this into my .profile
file
+# <<< brew configure <<<
+eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
+# <<< brew configure <<<
and it works just fine. It's just important not to forget to activate it before sourcing .bashrc
files if brew
is called inside it.
I've added this into my .profile file and it works just fine.
@uvlad7 On Ubuntu, it will source the ~/.profile
file when you log in to the GNOME session (if you have a GUI). If I understand correctly, all your terminal emulator sessions will be the child process of the GNOME GUI session. Correct me if I'm wrong.
For subshell, for example run bash
in a shell session:
$ # in a bash login session
$ bash # enter a subshell
bash:~$ # this is not a login shell and will only source `~/.bashrc`
the subshell will not source ~/.profile
anymore.
@XuehaiPan
If I understand correctly, all your terminal emulator sessions will be the child process of the GNOME GUI session. Correct me if I'm wrong. Yep, it works like so, despite the fact that it's actually a child of a systemd process
$ pstree -s $$ systemd───systemd───gnome-terminal-───bash───pstree
the subshell will not source
~/.profile
anymore. Yep. Actually, terminal emulators can be configured to run command as a login shell, and, as far as I know, Mac OS X’s Terminal.app is configured this way by default, but usually subshells aren't login shells. And it's OK forPATH
or other exported variables configuration:vladimir@np940x5n:~$ export DEBUG=true vladimir@np940x5n:~$ DEBUG=fasle vladimir@np940x5n:~$ echo $DEBUG fasle vladimir@np940x5n:~$ bash vladimir@np940x5n:~$ echo $DEBUG fasle vladimir@np940x5n:~$ exit vladimir@np940x5n:~$
but
vladimir@np940x5n:~$ DEBUG=fasle vladimir@np940x5n:~$ echo $DEBUG fasle vladimir@np940x5n:~$ bash vladimir@np940x5n:~$ echo $DEBUG
vladimir@np940x5n:~$ exit vladimir@np940x5n:~$
But it's not OK for competions. Look, I've removed them from my .bashrc and added into .profile, it doesn't work, because completions don't work in child processes
vladimir@np940x5n:~$ complete | grep brew vladimir@np940x5n:~$ if type brew &>/dev/null; then HOMEBREW_PREFIX="$(brew --prefix)"; if [[ -r "${HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh" ]]; then source "${HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh"; else for COMPLETION in "${HOMEBREW_PREFIX}/etc/bash_completion.d/"*; do [[ -r "${COMPLETION}" ]] && source "${COMPLETION}"; done; fi; fi vladimir@np940x5n:~$ complete | grep brew complete -o bashdefault -o default -F _brew brew vladimir@np940x5n:~$ bash vladimir@np940x5n:~$ complete | grep brew vladimir@np940x5n:~$
vladimir@np940x5n:~$ export DEBUG=true vladimir@np940x5n:~$ DEBUG=fasle vladimir@np940x5n:~$ echo $DEBUG fasle vladimir@np940x5n:~$ bash vladimir@np940x5n:~$ echo $DEBUG fasle vladimir@np940x5n:~$ exit vladimir@np940x5n:~$
but
vladimir@np940x5n:~$ DEBUG=fasle vladimir@np940x5n:~$ echo $DEBUG fasle vladimir@np940x5n:~$ bash vladimir@np940x5n:~$ echo $DEBUG vladimir@np940x5n:~$ exit vladimir@np940x5n:~$
@uvlad7 Only exported variables are environment variables that can be inherited to subshells. In your second example, the variable without export
keyword will have no effect in the new bash
session. That's why we usually see export PATH=...
.
But it's not OK for competions.
Completions are usually defined by functions rather than environment variables. They are not inherited. You need to eval the brew shellenv
command to enable it.
In the default configuration,
~/.bash_profile
will contain a statement to source~/.bashrc
.# ~/.bash_profile if [[ -f ~/.bashrc ]]; then source ~/.bashrc fi
I don't think this is universally the case. It's not on macOS. We should not be relying on the user having this, which makes .bashrc
largely not suitable for macOS (and yes people still use Bash on macOS).
You need to eval the brew shellenv command to enable it.
shellenv doesn't touch completions. It's purely about environment variables.
Only exported variables are environment variables that can be inherited to subshells. In your second example, the variable without export keyword will have no effect in the new bash session. That's why we usually see export PATH=....
Completions are usually defined by functions rather than environment variables. They are not inherited. You need to eval the brew shellenv command to enable it.
@XuehaiPan , that's exactly what I wanted to highlight in the examples
I don't think this is universally the case. It's not on macOS. shellenv doesn't touch completions. It's purely about environment variables.
@Bo98 that's why rcfiles aren't the right place for shellenv, and profile files are. It's about selecting the right profile file, not about moving everything into rcfiles, at least because there is no rc file for pure sh and people may want to use brew from it.
vladimir@np940x5n:~$ sh -x
$
I don't think this is universally the case. It's not on macOS. We should not be relying on the user having this, which makes .bashrc largely not suitable for macOS (and yes people still use Bash on macOS).
@Bo98 If the .bash_profile
is not loading .bashrc
, we need to add the shellenv command in both .bash_profile
and .bashrc
to support both login shell and non-login shell cases.
It's not on macOS. We should not be relying on the user having this, which makes
.bashrc
largely not suitable for macOS (and yes people still use Bash on macOS).
I wonder if we should just make this output vary definitely per-OS and perhaps per-distro as it seems there's no single option that works consistently everywhere.
If we really must pick one option, though: macOS takes priority: it has dramatically more users than Linux.
at least because there is no rc file for pure sh and people may want to use brew from it.
@uvlad7 We actively do not support this. This type of edge-case optimisation is not the right call here, sorry.
Just noticed an interesting thing that cat complicate debug process. So, eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
was in my .profile
. I tried to move it into .bash_profile
(noticed that .profile
was sourced twice and thought that it was sourced from .bash_profile
, and it was, but because I forgot to deactivate 'Run as login shell' option in my terminal emulator). So, I moved this line, logged out and logged back in - ooops, brew still was in my PATH. I was trying understand why hadn't it worked before, and finally decided to reboot my computer - ooops, brew wasn't in my PATH after that.
So, you can't just relogin to check your changes. I reproduced that behavior again: I moved initialization back into .profile
and added this
now=$(date +"%T")
echo "Current time : $now" >> debug
echo 'sourced .bash_profile' >> debug
echo $(ps -o args= $PPID) >> debug
echo $SHELL >> debug
echo >> debug
into .profile
, .bash_profile
and .bashrc
(default .bash_profile
sources .profile
and .profile
sources .bashrc
if shell is bash). Then, I rebooted the computer, checked that brew was in the path, did the same after a relogin, and finally rebooted the computer again and checked that brew wasn't in the path that time. Here is what I got in debug
(with comments)
# First reboot, login
Current time : 22:02:39
Sourced .profile
/usr/libexec/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu
/bin/bash
Current time : 22:02:39
sourced .bashrc
/usr/libexec/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu
/bin/bash
# Start gnome-terminal
Current time : 22:02:49
sourced .bashrc
/usr/libexec/gnome-terminal-server
/bin/bash
# Relogin
Current time : 22:03:37
Sourced .profile
/usr/libexec/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu
/bin/bash
Current time : 22:03:37
sourced .bashrc
/usr/libexec/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu
/bin/bash
# Start gnome-terminal
Current time : 22:03:47
sourced .bashrc
/usr/libexec/gnome-terminal-server
/bin/bash
# Second reboot, login
Current time : 22:04:31
Sourced .profile
/usr/libexec/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu
/bin/bash
Current time : 22:04:31
sourced .bashrc
/usr/libexec/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu
/bin/bash
Current time : 22:04:41
sourced .bashrc
/usr/libexec/gnome-terminal-server
/bin/bash
So, .profile
is sourced on relogin, but changes are ignored for some reason.
UPD: ENVs set during login are kept. I just added export DEBUG1=1
into the .profile
, relogged, changed it to export DEBUG2=2`, relogged, removed it, checked in terminal:
vladimir@np940x5n:~$ echo $DEBUG1 $DEBUG2
1 2
I wonder if we should just make this output vary definitely per-OS and perhaps per-distro as it seems there's no single option that works consistently everywhere.
I made profile
as default on macOS and rcfile
as default on Linux in PR #809.
@gromgit may have thoughts here.
I'd have to agree that the rcfile is the most pragmatic place to add brew shellenv
on Linux, because:
.profile
that didn't source .bashrc
.As for macOS, unless folks have been complaining that brew shellenv
doesn't work for them in .profile
, I think we should keep it as-is. I believe that's the state of play in #809?
install
oruninstall
script?brew config
andbrew doctor
and included their output with your issue? If you couldn't install: provided your OS version with the output of your issue? My OS is Ubuntu 22.04.3 LTS. I don't thinkbrew config
andbrew doctor
are relevant here, buthere is the output
What you were trying to do (and why)
I installed brew with the following command
and added this line
into my
.bash_profile
file, just like it suggested. Then, I evaluatedand brew worked just fine. Then I logged out and logged in back, expecting brew to work, but it didn't
What happened (include command output)
brew
wasn't found in the pathCommand output
What you expected to happen
I expected
brew
to be in the pathStep-by-step reproduction instructions (by running
brew
commands)It looks like I described it above, and I've found why it happened - Ubuntu doesn't source
.bash_profile
on login into Xorg session, it sources.profile
, despite$SHELL
is/bin/bash
, here is a bug. And I found that your docs says to add brew via.profile
on Ubuntu/Debian, so you must have been aware of this problem. But the Next steps instructions in the install script don't highlight it.