Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

contents: 设置环境变量配置源时是否应使用 .bashrc 而非 .bash_profile? #139

Open
SadPencil opened this issue Feb 16, 2024 · 10 comments

Comments

@SadPencil
Copy link
Contributor

SadPencil commented Feb 16, 2024

帮助页面的链接(Help page URL)

https://help.mirrorz.org/rustup/

原文 (Text)

若要长期启用镜像源,执行:

# for bash
echo 'export RUSTUP_UPDATE_ROOT=https://mirrors.tuna.tsinghua.edu.cn/rustup/rustup' >> ~/.bash_profile
echo 'export RUSTUP_DIST_SERVER=https://mirrors.tuna.tsinghua.edu.cn/rustup' >> ~/.bash_profile

反馈和修正 (Feedback)

若要长期启用镜像源,执行:

# for bash
echo 'export RUSTUP_UPDATE_ROOT=https://mirrors.tuna.tsinghua.edu.cn/rustup/rustup' >> ~/.bashrc
echo 'export RUSTUP_DIST_SERVER=https://mirrors.tuna.tsinghua.edu.cn/rustup' >> ~/.bashrc

备注 (Note)

.profile / .bash_profile 只有 interactive login shell (console 登录、SSH 登录)的情形会加载
.bashrc 只有 interactive non-login shell (GUI 启动 terminal、其他进程执行 bash)的情形会加载,但现代的发行版往往在 .profile 中 source .bashrc (注:可能需要进一步调查)

因此,在这里使用 .bash_profile 会对 GUI 用户造成一定的使用上的困扰,结合发行版实际,拟改为 .bashrc

@SadPencil
Copy link
Contributor Author

SadPencil commented Feb 16, 2024

不过这点可能有争议,我看 golang.google.cn 和 goproxy.cn 上依然写的是把环境变量设置写到 .profile 中,但这样也会对 GUI 用户造成困扰

我还不确定 .bashrc 是否在所有主流发行版中都会被 .profile 调用,亦或者反过来,可能需要统计不同发行版的行为


另,rust 官方安装程序 rustup-init 中是这么写的

The cargo, rustc, rustup and other commands will be added to
Cargo's bin directory, located at:

  /home/user/.cargo/bin

This path will then be added to your PATH environment variable by
modifying the profile files located at:

  /home/user/.profile
  /home/user/.bashrc

并列给出了 .profile 和 .bashrc

@taoky
Copy link
Member

taoky commented Feb 16, 2024

> rg bash_profile
contents/rustup.mdx
37:echo 'export RUSTUP_UPDATE_ROOT={{http_protocol}}{{mirror}}/rustup' >> ~/.bash_profile
38:echo 'export RUSTUP_DIST_SERVER={{http_protocol}}{{mirror}}' >> ~/.bash_profile

contents/homebrew-bottles.mdx
28:echo 'export HOMEBREW_API_DOMAIN="{{http_protocol}}{{mirror}}/api"' >> ~/.bash_profile
29:echo 'export HOMEBREW_BOTTLE_DOMAIN="{{http_protocol}}{{mirror}}"' >> ~/.bash_profile

contents/homebrew.mdx
67:  test -r ~/.bash_profile && echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.bash_profile
78:  test -r ~/.bash_profile && echo "eval \"\$($(brew --prefix)/bin/brew shellenv)\"" >> ~/.bash_profile
155:test -r ~/.bash_profile && echo 'export HOMEBREW_BREW_GIT_REMOTE="{{http_protocol}}{{mirror}}/brew.git"' >> ~/.bash_profile  # bash
156:test -r ~/.bash_profile && echo 'export HOMEBREW_CORE_GIT_REMOTE="{{http_protocol}}{{mirror}}/homebrew-core.git"' >> ~/.bash_profile
> rg bashrc
contents/julia.mdx
70:不同系统和命令行下永久设定环境变量的方式也不相同,例如 Linux Bash 下可以通过修改 `~/.bashrc` 文件实现该目的:
75:# ~/.bashrc

contents/git-repo.mdx
25:repo 的运行过程中会尝试访问官方的 git 源更新自己,如果想使用镜像源进行更新,可以将如下内容复制到你的`~/.bashrc`里

contents/flutter_infra.mdx
37:echo "export FLUTTER_STORAGE_BASE_URL=${FLUTTER_STORAGE_URL%/flutter_infra}" >> ~/.bashrc

contents/flutter.mdx
38:echo 'export FLUTTER_STORAGE_BASE_URL="{{http_protocol}}{{mirror}}"' >> ~/.bashrc

contents/dart-pub.mdx
29:echo 'export PUB_HOSTED_URL="{{http_protocol}}{{mirror}}"' >> ~/.bashrc

contents/rosdistro.mdx
29:# 为了持久化该设定,可以将其写入 .bashrc 中,例如
30:echo 'export ROSDISTRO_INDEX_URL={{http_protocol}}{{mirror}}/index-v4.yaml' >> ~/.bashrc

一个需要关注的问题是,似乎 macOS 的 bash 不会 source .bashrc(需要验证)。

@SadPencil
Copy link
Contributor Author

SadPencil commented Feb 18, 2024

根据目前的不完全统计

~/.bash_profile 调用 ~/.bashrc 的发行版包括:

  • Arch Linux、Debian、Ubuntu、Rocky (应当可以类推到其他 RHEL 系)
  • NixOS 的 Home Manager (裸的 NixOS 的话这俩文件是空的)

~/.bash_profile 和 ~/.bashrc 没有调用关系的发行版包括:

  • OpenSUSE、Clear Linux
    注:这两个发行版存在 /etc/bash.bashrc 调用 /etc/profile 的情况。但不涉及用户配置文件的相互调用,因此仍然看作没有调用关系。
  • macOS (老)【可能需要更多统计样本】
  • macOS(新)默认使用 zsh,.zshrc 和 .profile 互相没有调用关系【可能需要更多统计样本】

注:为简洁叙述起见, .bash_profile 也包括此文件不存在但 .profile 存在的情况。

@AethoceSora
Copy link
Contributor

@taoky

一个需要关注的问题是,似乎 macOS 的 bash 不会 source .bashrc(需要验证)。

经验证,MacOS 14.1.2 (23B92),bash version 3.2.57(1)-release 可正常调用 ~/.bashrc

@SadPencil
Copy link
Contributor Author

SadPencil commented Feb 18, 2024

@taoky

一个需要关注的问题是,似乎 macOS 的 bash 不会 source .bashrc(需要验证)。

经验证,MacOS 14.1.2 (23B92),bash version 3.2.57(1)-release 可正常调用 ~/.bashrc

不是这个意思。他应该是说 macOS 的 .profile 没有写去 source .bashrc,不是指 bash 启动时是否访问这个文件 (bash 启动时访问 profile 还是 rc 只看自己是不是 login shell)

@SadPencil
Copy link
Contributor Author

SadPencil commented Feb 18, 2024

我刚才找人测试了 macOS 下打开图形界面的 terminal 时的情况,与 Linux 表现一致,即此时 zsh/bash 会把自己算作 non-login shell 因此 ~/.(bash_)profile 不会被加载。如果这个测试成立的话,homebrew-bottles.mdxhomebrew.mdx 为何会把 env 写到 ~/.bash_profile 呢,不理解。

@taoky
Copy link
Member

taoky commented Feb 18, 2024

如果这个测试成立的话,homebrew-bottles.mdxhomebrew.mdx 为何会把 env 写到 ~/.bash_profile 呢,不理解。

按照 brew 提供的 manpage:

The variables HOMEBREW_PREFIX, HOMEBREW_CELLAR and HOMEBREW_REPOSITORY are also exported to avoid querying them multiple times. To help guarantee idempotence, this command produces no output when Homebrew’s bin and sbin directories are first and second respectively in your PATH. Consider adding evaluation of this command’s output to your dotfiles (e.g. ~/.bash_profile or ~/.zprofile on macOS and ~/.bashrc or ~/.zshrc on Linux) with: eval "$(brew shellenv)"

Append these options to all cask commands. All --*dir options, --language, --require-sha, --no-quarantine and --no-binaries are supported. For example, you might add something like the following to your ~/.profile, ~/.bash_profile, or ~/.zshenv:

emmm,我没有特别的偏好,只是看起来之前没有人考虑清楚这个问题。(至少 homebrew 看起来更倾向于在 macOS 上改 profile)

@SadPencil
Copy link
Contributor Author

SadPencil commented Feb 18, 2024

@taoky “至少 homebrew 看起来更倾向于在 macOS 上改 profile”的问题在于,这样修改之后,在图形界面中打开 terminal (相信也是大多数 mac 用户最常用的办法)并不会加载 profile (根据我刚才的测试得出;这样也符合 shell 的设计逻辑,因为本来这种场景就不是 login shell),也就是相当于没设置。不知道问题出在哪里,可能是我的测试有误,需要扩大 macOS 样本数量。

@taoky
Copy link
Member

taoky commented Feb 22, 2024

今日阅读到了一段关于 .profile 与 .bashrc 的论述,供参考(来源):

今天升级了 Debian 11,顺便学习了一下怎么确保所有程序都拿到一些环境变量(如 locale 相关环境变量)。以下说明虽然并不完全精确,但或许会让理解相关概念简单一些。

环境变量应该在进程树中尽可能高的地方被设置一次,之后不要重复设置,一直从父进程继承。.profile 文件一般是用来做这件事的。在 sh 的时代,实现这个目标比较简单:如果 sh 发现自己是 login shell,说明用户刚刚登入,自己是这个用户的进程树中最高的进程,所以应该加载 .profile 文件。如果不是 login shell,则不加载。

在 bash 的时代,为了和 sh 保持一致,虽然可以有 .bash_profile,但 bash 也读属于 sh 的 .profile。因此无须专门创建 .bash_profile,用 .profile 即可。

但是 bash 还有另外一项功能,就是在每次启动时(如果是交互式)执行 .bashrc,以便设置一些无法从父进程继承的配置,例如 PS1 或 alias。不知由于什么原因,bash 被设计为如果读了 .profile,就不会读 .bashrc,虽然 .bashrc 的内容明明应该是每次交互式执行都需要的。为了解决这个问题,一般都在 .profile 中检查当前进程是不是 bash,如果是,就读 .bashrc,这样恰好修复了 bash 的这个问题。其他 shell 如果有类似问题,也应当这样修复。

这时,.profile 和 .bashrc 的区别就很明确了,前者应该存放环境变量等“只需设置一次,所有程序都要用”的信息,后者则仅仅是 bash 这一个软件内部的配置,和各种其他软件的 rc 文件类似。这样编写内容后,如果有软件不按这样的思想工作,应该设法修复。

例如,在桌面系统中,从图形界面登录后,会发现 .profile 没有被加载过,那就要设法让 display manager 程序(用户的进程树的顶端)加载 .profile。有的系统中相关软件被配置为会读取 .xprofile 文件,Debian 系统则规定一律使用 .xsessionrc 文件。因此对于我来说,在 .xsessionrc 文件中写上一行载入 .profile 的命令即可。

如果通过 ssh 连接远程机器,因为登录后启动的第一个进程会是 bash,所以它会作为 login shell 读取 .profile,没有问题。

如果把这些文件放进了 docker 中(虽然这样做有点奇怪👀),然后直接在 docker 中启动 bash,会发现 bash 并不读取 .profile,因为不是 login shell,这又违反了上面说的思想。可以通过以 root 身份执行 login -f username 解决,这会启动一个 login shell,确保读取 .profile。这还有额外的好处,login 会设置一些基础环境变量,例如 USER SHELL 等(不走这个流程的话默认是没有这些变量的),还会进入用户家目录,产生一个相当正常的环境。

@SadPencil
Copy link
Contributor Author

SadPencil commented Feb 22, 2024

今日阅读到了一段关于 .profile 与 .bashrc 的论述,供参考(来源):

这段话的作者认为环境变量应当在尽可能早的时候定义,并且 .profile 是合适的节点,我对此并不完全同意。

  1. bash 并不会保证读取 .profile 文件(当然我说的是 login shell 的情形)。.profile 仅作为 .bash_profile 文件不存在时的 fallback(并且fallback了不止一次才会轮到)
  2. zsh 并不会读取 .profile(同上,我强调的是 login shell 也不会读取),而是读取 .zprofile
  3. 桌面系统默认也不读取 .profile,同样需要手动修改相关配置文件

因此,作者为了希望实现所有交互进程能有共同的环境变量配置文件这一点,强行让 .profile 充当了这一角色,这更多体现的是作者本身的意志。

另一个角度,将环境变量配置工作从普通 shell 移动到 login shell 或者桌面系统这种父节点,也就意味着用户需要重新登录后才可使新的环境变量生效,为了追求形式上的优雅,要忍受不便利。就连 Windows 都提供了不注销刷新环境变量的 API,所以用户通过系统设置修改完环境变量或者用 Inno Setup 安装包安装完软件后 PATH 的更改会立刻通知到所有 Windows 进程,而无需重新登录或者重启。而非 Windows 用户更不会接受为了安装软件而重启/结束当前会话这种事情。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants