非登录 shell 将 $HOME/[.local/]bin 源到 $PATH,我找不到原因

noc*_*rea 2 command-line bash login environment-variables 22.04

操作系统:Ubuntu桌面22.04

我最初以用户 carl 身份登录。我打开一个 shell 并 echo $0,我得到确认,我处于非登录 shell 中。(“bash”,没有破折号)但是当我 echo $PATH 时,我看到 $HOME/.local/bin 和 $HOME/bin 都是来源的,它既没有在 ~/.bashrc 中也没有在 /etc/environment 中声明。

该线程的答案表明从登录用户继承。

所以我测试了一些东西:

    $ su - root
    $ echo $0
    > -bash
    $ echo $PATH
    > /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
    $ su carl
    $ echo $0
    > bash
    $ echo $PATH
    > /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
    $ su - carl
    $ echo $0
    > -bash
    $ echo $PATH
    > /home/carl/.local/bin:/home/carl/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
    $ su carl
    $ echo $0
    > bash
    $ echo $PATH
    > /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
Run Code Online (Sandbox Code Playgroud)

在此示例中,以 root 身份登录后,然后切换到非登录用户 shell,PATH 变量就如其应有的那样。然后我检查是否以 carl 身份登录,然后切换到非登录 shell,因为 carl 继承了登录的 shell 变量,但事实并非如此。

其他注意事项:

  • 未选中“作为登录 shell 运行命令”
  • .bashrc 中没有对源 .profile 或任何其他文件的交叉引用
  • 不存在 .bash_login 或 .bash_profile 文件
  • 重启没有任何改变

我正式不再猜测,非常感谢企鹅大师来启发我,以便我可以再次入睡。

Dan*_*l T 6

.local/bin默认情况下添加(~/.profile复制自/etc/skel/.profile):

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
    PATH="$HOME/.local/bin:$PATH"
fi
Run Code Online (Sandbox Code Playgroud)

.profile是改的地方正确PATH,不是.bashrc

.bashrc 中没有对源 .profile 或任何其他文件的交叉引用

不,情况恰恰相反。.profile来源.bashrc

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi
Run Code Online (Sandbox Code Playgroud)

让我们看一下你的例子:

$ su - root
$ echo $0
-bash # This is a root login shell. It sources /root/.profile
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ su carl
$ echo $0
bash # This is a user non-login shell. It sources .bashrc not .profile
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ su - carl
$ echo $0
-bash # This is a user login shell. It sources .profile not .bashrc
$ echo $PATH
/home/carl/.local/bin:/home/carl/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ su carl
$ echo $0
bash # This is a user non-login shell. It sources .bashrc not .profile
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
Run Code Online (Sandbox Code Playgroud)

如果我强行(不推荐)使用su登录而不通过登录外壳,我不会得到我$PATH想要的正常结果:

home@daniel-desktop3:~$ su home
Password: 
home@daniel-desktop3:~$ echo $0 # Non-login shell. Didn't get .profile
bash
home@daniel-desktop3:~$ echo $PATH # Missing what I want
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
home@daniel-desktop3:~$ bash # Start nested shell
home@daniel-desktop3:~$ echo $0
bash
home@daniel-desktop3:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
home@daniel-desktop3:~$ exit # Exit nested shell
exit
home@daniel-desktop3:~$ exit # Exit su shell
exit
Run Code Online (Sandbox Code Playgroud)

但是,如果我正常登录,$PATH应该会被export编辑到子 shell。su - username当您通过GUI登录时,它应该.profile设置$PATH. 然后这个变量将从桌面环境的进程继承,然后是终端模拟器,然后是在其中运行的 bash。

home@daniel-desktop3:~$ su - home
Password: 
home@daniel-desktop3:~$ echo $0 # Login shell sources .profile
-bash
home@daniel-desktop3:~$ echo $PATH # I get the path I want
/home/home/.elan/bin:/home/home/bin:/home/home/.cargo/bin:/home/home/kde/src/kdesrc-build:/home/home/.cabal/bin:/home/home/.ghcup/bin:/home/home/.local/bin:/opt/rocm-6.0.0/bin:/home/home/.go/bin:/home/home/.nvm/versions/node/v21.6.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/home/.local/share/JetBrains/Toolbox/scripts
home@daniel-desktop3:~$ bash # Start a subshell
home@daniel-desktop3:~$ echo $0 # .bashrc is sourced again. .profile is NOT sourced. $PATH is INHERITED
bash
home@daniel-desktop3:~$ echo $PATH # I inherit $PATH like I want
/home/home/.elan/bin:/home/home/bin:/home/home/.cargo/bin:/home/home/kde/src/kdesrc-build:/home/home/.cabal/bin:/home/home/.ghcup/bin:/home/home/.local/bin:/opt/rocm-6.0.0/bin:/home/home/.go/bin:/home/home/.nvm/versions/node/v21.6.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/home/.local/share/JetBrains/Toolbox/scripts
home@daniel-desktop3:~$ exit # Exit nested non-login subshell
exit
home@daniel-desktop3:~$ exit # Exit login shell
logout
Run Code Online (Sandbox Code Playgroud)

因此,在 GUI 登录中,以下是简化视图(忽略systemd中间的细节和其他过程):

  • gdm3作为根用户
    • gnome-session或另一个DE。这个来源.profile
      • gnome-terminal。不来源任何东西。继承$PATH
        • bash。这是您的非登录子 shell。其来源.bashrc并非如此.profile。它$PATH通过 gnome-terminal 继承自 gnome-session
          • bash。如果您再次输入,这是一个子 shell bash。与上面做同样的事情

对于 SSH/su - username登录(也忽略 PAM 详细信息):

  • sshd作为根用户
    • -bash这是您的登录 shell。这来源 .profile。除非告诉它 .bashrc,否则它不会直接获取.profile
      • bash如果您再次键入,这是一个非登录子 shell bash。其来源.bashrc并非如此.profile。它直接继承$PATH-bash
        • bashbash如果您再次键入,这是另一个嵌套的非登录子 shell 。它的作用与其他非登录子 shell 相同。它继承$PATH-bashviabash

这是预期的行为。尝试更改它可能会导致出现重复条目$PATH​​并且变得太长的错误。

$PATH如果您确实希望在非登录 shell 中使用原始较短的内容,您可以添加一些代码~/.bashrc来检测这种情况,并解析并删除$PATH.