提出这个问题的动机如下:
我使用的是 Ubuntu 12.04 LTS 2 和 Unity 桌面。在我的 .bashrc 文件中,我将几个目录附加到 PATH 变量并定义一些环境变量,例如 JAVA_HOME。当我从终端启动应用程序(运行 bash,我的默认 shell)时,这很有效,但对于使用 Unity 启动器的几个快捷方式,它们运行的应用程序似乎被定义为使用 #!/bin/sh(别名为 /bin/dash),并且它们不会获取 ~/.bashrc 或 ~/.profile 的内容。
我想我可以将所有这些快捷方式改为使用 /bin/bash 而不是 /bin/sh,以强制它获取 .bashrc 更改,但这似乎真的很不方便。
鉴于 Ubuntu 12.04(默认情况下)将 /bin/sh 别名为 /bin/dash,并且我的默认 shell 是 /bin/bash,是否有一个地方我可以选择修改 PATH 并定义环境变量,如果我希望它们存在于全部这些情况:
- 每当我创建一个非登录 bash shell(使用 unity 中的终端)
- 每当我创建一个登录 bash shell(例如,通过 ssh 远程登录)
- 每当我使用 Unity 应用程序启动器时(假设启动器使用 /bin/sh)。
- 每当 cron 作业执行时(假设 /etc/crontab 中的 SHELL=/bin/sh)。
如果我理解正确的话,我猜测:
- (1)/(2)和(3)/(4)不同,因为(1)/(2)是 bash 而(3)/(4)是 dash。
- (1) 和 (2) 不同,因为 bash 选择加载的文件根据它是否是登录 shell 而不同。
- (3)和(4)不同,因为(3)会在某个时刻出现后我已经登录(因此 ~/.profile 将由它的一个父进程获取,而(4)将在我登录时获取。不是登录,因此 ~/.profile 将不会被读取。
(如果其他因素也很重要,我不会感到惊讶,例如 shell 是否具有交互性,因此可能还有更多我甚至没有预料到的组合……在这种情况下,我很高兴我的问题得到“改进”。)
我希望在某个时候,有人必须制作某种指南,告诉您如何/在哪里以独立于 shell 的方式(或至少以 dash/bash 兼容的方式)修改环境变量......我只是似乎找不到正确的搜索词来找到这样的指南。
非常感谢解决方案或解决方案的指示!
更新:
- 澄清:这是 12.04 安装过程中创建的默认 Ubuntu 用户,因此没什么特别的。它做有一个 ~/.profile (明确来源 ~/.bashrc),并且唯一存在的 ~/.bash* 文件是 .bashrc、.bash_history 和 .bash_logout……所以没有 .bash_profile。
- 强调范围:除了默认交互式 shell(bash)和碰巧使用 /bin/sh(别名为 dash)的任何脚本之外,我并不真正关心任何 shell,因此没有必要用任何东西来复杂化这一点额外的用于 tcsh/ksh/zsh/etc 的支持。
答案1
Shell 调用有点复杂。bash 和 dash 手册页中INVOCATION
有关于此内容的部分。
总结来说(手册页中有更多详细信息,您应该阅读):
When bash is | it reads
-------------------------------|----------
login shell | /etc/profile and then the first of ~/.bash_profile, ~/.bash_login or ~/.profile that exists.
|
interactive non-login shell | /etc/bash.bashrc then ~/.bashrc
|
non-interactive shell | The contents of $BASH_ENV (if it exists)
|
interactive (as "sh") | The contents of $ENV (if it exists)
-
When dash is | it reads
-------------------------------|---------
login shell | /etc/profile then .profile
|
interactive shell | The contents of ENV (it it exists, can be set in .profile as well as in initial environment)
我不知道其他 shell 的情况,因为我从未使用过它们。最好的办法可能是设置几个环境变量来指向公共位置脚本,并在几种未涵盖的情况下手动获取该脚本(适当时)。
答案2
因此,有几种方法可以解决这个问题。许多人会选择以下方法:
a. 有一个文件,其中包含所有 sh 风格 shell 所共有的内容,例如.shcommon
在每个等等中.profile
.bashrc
.kshrc
,只需使用以下命令获取该文件. .shcommon
b. 将所有内容放入.profile
并从其他文件中获取。
然后,可以在采购之前将特定 shell 或交互式和非交互式 shell 所需的内容放入相应的文件中.shcommon
就我个人而言,我不喜欢管理多个文件。因此,我使用以下方法:
首先,我需要的一切都进入了,.profile
因为我确实有一些 bash 和 ksh 特定的东西,所以我使用以下命令确定当前的 shell 名称:
# get name of current shell
# strip leading - from login shell
export SHELLNAME="${0#-}"
然后像下面这样为特定的 shell 输入命令(有些人更喜欢使用 case 语句)。
if [ "$SHELLNAME" = 'bash' ]
then
shopt -s checkwinsize
elif [ "$SHELLNAME" = 'ksh' ]
then
stty erase ^?
fi
如果我有只能在交互式 shell 中运行的命令,我会使用以下命令:
# check for interactive flag i in shell options $-
# in bash and ksh you could use the following, but breaks in dash
# if [[ $- == *i* ]]
if [ "$(echo $- | grep i)" != "" ]
then
fortune
fi
例如,所有 sh 风格的 shell 中常见的内容PATH
都可以放在顶部。
然后,我使用符号链接在所有 sh 样式的 shell 中加载同一个文件:
ln -s .profile .bashrc
ln -s .profile .kshrc
一些旁注,如果您有.bash_profile
,那么 bash 将加载它而不是.profile
但 dash 和 ksh 仍然会加载.profile
这可能是您问题的一部分。
此外,您可能需要考虑#!/bin/bash
在脚本中使用而不是,除非#!/bin/dash
您确实想要 POSIX 兼容脚本。bash 有很多非常好的额外功能,并且以 sh 形式调用 dash 或 bash 将禁用其中许多功能。
此外,bash 手册页很好地解释了.profile
versus何时.bashrc
加载。类似的规则也适用于 ksh。dash.profile
在登录时加载,并允许您在交互式 shell 启动时加载使用ENV
环境变量指定的文件.profile
(也请查看 dash 手册页并搜索 .profile)。
答案3
由于情况 (1) 和 (2) 是通过在 .bashrc 和 .profile 中获取我的环境变量来解决的,因此真正的问题是“我为 (3) 和 (4) 获取这些相同变量的文件的名称是什么”。
看起来有askubuntu 上问题(如何获取要在 Unity 桌面中导入的环境变量)第 (3) 部分的答案。建议创建一个 ~/.xsessionrc 文件,该文件将由 /etc/X11/Xsession 提供。(我试过了,似乎有效……耶!)
我仍然对 (4) 做什么感到困惑。当然,如果我创建一个 cron 作业(或守护进程),我可以用类似“bash -i -c /bin/foo”之类的命令替换“/bin/foo”,以强制它使用 bash 加载正确的环境变量,但这也意味着我必须修改可能代表我安装守护进程任务或 cron 作业的任何第三方工具。真恶心。