![对于每种情况我应该使用哪个 bash 配置文件?](https://linux22.com/image/931726/%E5%AF%B9%E4%BA%8E%E6%AF%8F%E7%A7%8D%E6%83%85%E5%86%B5%E6%88%91%E5%BA%94%E8%AF%A5%E4%BD%BF%E7%94%A8%E5%93%AA%E4%B8%AA%20bash%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%EF%BC%9F.png)
我已经看到了很多关于 以及各种其他配置文件如何交互的详细解释.bashrc
,.bash_profile
所以我并不想解释它们是如何组合在一起的(我读过很多这样的解释,但没有一个能回答如何处理下面的问题)。我真正想知道的是实现以下场景的最佳方式或最佳实践或最合理的方式或最有效的方式(在我看来,清晰度、逻辑性和效率是最好的):
如果我想要一行仅在打开任何新的图形终端时运行的 bash 代码,我应该将该代码放入哪个文件中?
如果我想要一行仅在登录任何新的交互式 shell 时运行的 bash 代码,我应该把该代码放在哪里?
如果我想要一行打开的 bash 代码两个都图形终端和交互式登录 shell,我应该把该代码放入哪个文件中?
• 重点:为了强调,我希望上述代码行仅有的在打开 shell 或终端时运行,并且不是在我启动的任何旧单行echo "Hello World!"
脚本调用期间运行。即我希望这些仅在我选择打开 shell/终端,然后开始输入其他脚本不是包括那个。应该很简单,对吧?
我对此感到很困惑,因为这些问题应该很容易回答,但我从来没有看到过答案。我有看到了很多关于我们必须.profile
从 进行dotsource 的难以捉摸的答案.bashrc
,或者可能是反过来(取决于天气)以及“你必须阅读文档 x 和文档 y,并且然后一切都会清楚!”——答案越来越复杂,很难对上述三种情况给出简单/清晰/明确的答案。真的想知道将每段代码放入哪个文件以便它可以在该场景中运行吗?我不介意实现这一点所需的最小框架。即“对于场景 3,添加代码,但为了file-x
方便,您还必须将以下if-then-fi
块放入file-y
”,但如果这三种情况的答案可以跨平台(即适用于 debian/ubuntu、centos/red hat、MacOS、suse 等的一站式解决方案,以及适用于图形终端的 Gnome/KDE/MacOS 等),那将是一个巨大的奖励。如果没有合理/逻辑的方法来实现这一点,那么至少可以说令人失望,但希望我错了!希望有人能向我展示一个清晰、高效、希望跨平台(但我知道这个要求可能太高)、可重复、简单、明确的方式来实现上述目标。
答案1
我的建议。
~/.bashrc
场景 1:像这样输入命令:([[ "$TERM" == "xterm"* ]] && run-command
测试终端是否为 xterm)
场景 2:输入命令(如果仍想运行该命令,~/.bash_login
请记住输入 source )~/.bashrc
~/.bashrc
场景 3:像这样输入命令:([[ $- == *"i"* ]] && run-command
测试 shell 是否是交互式的)
据我所知,我在我的 中使用这些选项.bashrc
,其目的或多或少与您想要的目的相同。
答案2
bash
识别三种 shell 状态:
- 登录 shell - 通过 ssh 或文本控制台等方式登录服务器直接调用的 shell 实例
- 交互式 shell - 任何可以输入命令的 shell,例如,在图形终端中启动的 shell。登录 shell 通常也是交互式 shell。
- 非交互式 shell - 这通常是从某个程序内部调用的 shell,用于运行另一个程序或命令。顾名思义,非交互式 shell 中没有与用户的交互。例如,如果您使用 ssh 在远程计算机上仅运行单个命令(如
ssh host.domain ls -l /etc
),那么您将隐式调用远程计算机上的非交互式 shell,而该 shell 依次运行该命令,然后退出。
启动文件的工作原理:
- A登录外壳执行来自
/etc/profile
(即所有用户的全局文件)的命令,然后按顺序在各个用户的主目录中查找文件.bash_profile
,.bash_login
或 - 按该顺序 - 并执行最先找到的文件的命令。在 Ubuntu 中,默认情况下只有文件存在,默认情况下它还包含用于执行文件内容的命令。但是,您可以从文件中删除要运行的代码,也可以使用所需的命令创建其他两个文件中的任何一个,然后不会运行。.profile
.profile
.bashrc
.bashrc
.profile
.profile
- 一个交互的(但未登录) shell 从
/etc/bash.bashrc
(对所有用户都是全局的) 执行命令,然后从.bashrc
各个用户主目录中的文件执行命令 - 非交互式炮弹开始本地(即从程序内部,或通过
bash
在终端窗口中输入)不要运行任何这些文件 - 非交互式炮弹开始来自网络(例如,在上面的例子中,您通过 ssh 在远程计算机上运行命令)
.bashrc
仅从用户主目录中的文件执行命令。但是,默认的 Ubuntu.bashrc
文件在开头包含一段代码,如果 shell 是非交互式的,则该代码将停止进一步执行。
在具体情况下还有一些更微妙的事情,但基本上它的工作原理如上所述。
因此解决方案取决于您是否要保留.profile
和.bashrc
文件的当前默认内容。
如果你想保留它们:
- 对于情况 1)您可以使用 Artur 的解决方案(但请记住,您的代码不仅会在登录后或启动终端后运行,还会在您启动另一个 shell 实例时运行,例如,只需
bash
在终端会话中键入内容即可。如果您想避免这种情况,您应该稍微修改解决方案:[[ "$TERM" == "xterm"* ]] && [ "$SHLVL" = "1" ] && run-command
- 对于情况 2),将代码放入
.profile
- 对于情况 3),只需输入您的代码
.bashrc
(只需记住插入它以下在 shell 为非交互式的情况下退出的初始代码)。但是,请记住,与情况 1) 类似,每当您启动另一个 shell 实例时,您的代码都会运行,因此为了避免这种情况,它应该像[ "$SHLVL" = "1" ] && run-command
如果您想为所有用户而不是只为您自己执行此操作,请使用/etc/bash.bashrc
和/etc/profile
文件而不是~/.bashrc
和~/.profile
。
如果要删除默认值:
- 重命名
.bashrc
为其他名称(以便以后改变主意时可以恢复) - 创建一个空的
.bash_profile
或.bash_login
文件然后: - 对于情况 1),请按上述操作
- 对于情况 2),请将代码放入
.bash_profile
或.bash_login
(无论你创建了哪个文件) - 对于情况 3),首先将要运行的代码添加
.bashrc
到您的.bash_profile
或.bash_login
文件(无论您创建了哪个文件),因为默认情况下它不存在。然后使用 Artur 的解决方案 - 但是,与上述情况 1) 类似,可以选择将其修改为以下形式[[ $- == *"i"* ]] && [ "$SHLVL" = "1" ] && run-command
对于系统范围的文件(/etc/bash.bashrc
和/etc/profile
),我不建议删除默认值:)
答案3
我用:
~/.profile
设置我的环境变量- 这在 bash 中有效,但也可以向其他 GUI 应用程序公开变量
- 看https://help.ubuntu.com/community/EnvironmentVariables#Persistent_environment_variables
- .profile 是 bash 的第三个选择,因此请确保您没有 ~/.bash_profile 或 ~/.bash_login
~/.bashrc
为了- 别名和函数
- 交互式 shell 的变量和设置
请注意,~/.profile 不是特定于 bash 的,因此不要使用特定于 bash 的命令。这意味着
# export FOO=bar # bad
FOO=bar; export FOO # good
由于我的 GUI 终端应用程序都配置为使用登录 shell,因此在我的 ~/.profile 中我输入了以下内容:
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
另外,我喜欢保持 PATH 整洁,没有重复,因此不要使用
PATH="$PATH:/some/path/1"
PATH="/some/path/2:$PATH"
我有
pathmunge () {
case ":${PATH}:" in
*:"$1":*)
;;
*)
[ ! -d "$1" ] && return
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
esac
}
# then
pathmunge "/some/path/1" after
pathmunge "/some/path/2" before
pathmunge "/some/path/1" before # already in PATH, no changes made