我应该在哪里导出环境变量,以便bash / dash,交互式/非交互式,登录/非登录的所有组合都能使用?


11

这是该问题的动机:

我在Unity桌面上使用Ubuntu 12.04 LTS 2。在我的.bashrc文件中,我将几个目录附加到PATH变量中,并定义了一些环境变量,例如JAVA_HOME。当我从终端(运行bash,我的默认shell)启动应用程序时,这很好用,但是对于使用Unity启动器的一些快捷方式,它们运行的​​应用程序似乎被定义为使用#!/ bin / sh,是/ bin / dash的别名,并且它们不会选择〜/ .bashrc或〜/ .profile的内容。

我想我可以将所有这些快捷方式更改为使用/ bin / bash而不是/ bin / sh来强制它获取.bashrc更改,但这似乎确实很hack。

鉴于Ubuntu 12.04(默认情况下)将/ bin / sh别名为/ bin / dash,并且我的默认外壳程序为/ bin / bash,是否有一个地方可以选择修改PATH并定义环境变量(如果需要)在所有这些情况下存在:

  1. 每当我创建非登录bash shell时(统一使用终端)
  2. 每当我创建登录bash shell时(例如,通过ssh远程登录)
  3. 每当我使用Unity应用程序启动器时(假设启动器使用/ bin / sh)。
  4. 每当执行cron作业时(假设/ etc / crontab中的SHELL = / bin / sh)。

如果我理解正确,我猜是这样的:

  • (1)/(2)和(3)/(4)不同,因为(1)/(2)是bash,而(3)/(4)是破折号。
  • (1)和(2)是不同的,因为bash选择加载的文件取决于它是否是登录shell而有所不同。
  • (3)和(4)是不同的,因为(3)将我登录后的某个时刻出现(因此〜/ .profile将由其父进程之一提供,而(4)将在某个时候出现点的时候我我登录,因此〜/ .profile文件将不会被读取。

(如果其他因素也很重要,例如外壳是否是交互式的,我也不会感到惊讶,因此,我什至没有想到更多的组合……我很高兴提出“改进了我的问题“ 在这种情况下。)

我希望在某个时候,有人一定已经制定了某种指南,告诉您如何/在何处以与外壳程序无关的方式(或至少与破折号/重击兼容的方式)修改环境变量...我只是可以似乎找不到合适的搜索词来找到这样的指南。

解决方案或解决方案的指针,不胜感激!

更新:

  • 说明:这是由12.04安装过程创建的默认Ubuntu用户,因此没有什么幻想。它确实有一个〜/ .profile(显式来源〜/ .bashrc),并且仅存在的〜/ .bash *文件是.bashrc,.bash_history和.bash_logout ...所以没有.bash_profile。
  • 关于范围重点:我真的不关心不是默认的交互式shell(bash)的,并且发生在使用/ bin / sh的(别名为破折号)任何脚本之外的任何炮弹,所以没有必要与任何复杂这个额外的tcsh / ksh / zsh / etc。支持。

2
将其放在一个文件中,然后让其他rc文件作为源。
konsolebox

根据仪表板手册页,我在这里应将$ HOME / .profile读为登录shell。
伊坦·赖斯纳

@konsolebox哪些rc文件?AFAICT,破折号没有rc文件。正如我所说,破折号似乎并没有收集〜/ .profile的内容。

@EtanReisner是的,这就是问题的重点。如果破折号没有作为登录外壳运行(因此〜/ .profile不是源文件),那该怎么办?

@Mickalot您是否以交互方式运行破折号?如果没有,请尝试向其添加-l选项。
konsolebox

Answers:


9

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)

我不了解其他外壳,因为我从不使用它们中的任何一个。最好的选择是设置几个环境变量以指向公共位置脚本,并在没有涉及的几种情况下手动(适当时)将其来源。


可悲的是,这个问题的症结在于仪表板中缺少的那个问题。当Unity桌面调用以#!/ bin / sh开头的任何脚本时,它将启动(我假设是)非登录,非交互的破折号外壳。所以,问题是:如何让我同样的环境变量可是存在其他任何地方的矩阵?

对。我想这就是bash为该插槽添加BASH_ENV的原因。鉴于破折号似乎在该插槽中没有任何作用,我不确定您可以在不影响启动破折号的应用程序环境变化(例如破折号继承)的情况下解决该问题。这将需要在X环境中设置环境变量,这是@Mickalot的.xsession(rc)注释起作用的地方。正如他指出的那样,这仍然遗漏了第四项(但我认为这实际上是故意的)。
Etan Reisner 2013年

由于我使用的是Ubuntu 12.04 LTS,因此cron实际上是pixie-cron,因此我可以在crontab文件中定义env变量...我猜SHELL = / bin / bash和BASH_ENV =〜/ .bashrc应该这样做吗?

3

因此,有几种方法可以解决此问题。许多人会:

一种。例如,有一个文件具有所有sh风格的shell共有的文件,.shcommon并且在每个.profile .bashrc .kshrcet cetra中,只需使用. .shcommon

b。放入所有内容,.profile并从其他文件中获取。

然后,可以在采购之前将特定外壳或交互式外壳与非交互式外壳所需的内容放入适当的文件中 .shcommon

我个人不喜欢管理多个文件。因此,我使用以下方法:

首先,我需要.profile 做的所有事情由于我确实有一些bash和ksh特定的东西,因此我使用以下命令确定当前的shell名称:

# get name of current shell
# strip leading - from login shell
export SHELLNAME="${0#-}"

然后在如下所示的内容中提供针对特定外壳的命令(某些命令更喜欢case语句)。

if [ "$SHELLNAME" = 'bash' ]
then
    shopt -s checkwinsize

elif [ "$SHELLNAME" = 'ksh' ]
then
    stty erase ^?
fi

如果我有只能在交互式外壳程序中运行的命令,请使用以下命令:

# 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会加载而不是.profiledash和dash和ksh仍会加载.profile 这可能是您问题的一部分。

此外,除非您确实想要POSIX兼容脚本#!/bin/bash#!/bin/dash否则您可能要考虑在脚本中使用。bash有很多非常不错的附加功能,并且像sh那样调用dash或bash会禁用许多这些功能。

另外,bash手册页很好地解释了何时加载.profilevs。.bashrc类似的规则适用于ksh。破折号.profile在登录时加载,并允许您在使用ENV环境变量中指定的交互式外壳启动时加载文件.profile(也请检查破折号手册页并搜索.profile)。


您能不能仅测试$ 0作为shell名称?是否有不起作用的外壳/盒?
伊坦·赖斯纳

同样,以$-检查i是否不足以进行交互式shell测试?(它将在没有我授予的tty的情况下在交互式shell上触发,但这可能会或可能不会产生不良影响。)
Etan Reisner 2013年

@Etan:嗯,我知道我第一次尝试$0并遇到了问题...我似乎无法确切地记得它们到底是什么。直接登录到控制台的确显示$0-bashbash但可以纠正。

@伊坦:是的,检查我$-也可以。我将不得不考虑何时需要一个没有tty的交互式外壳?由于某些原因,您的解决方案确实具有更好的“感觉”,我可能会对此进行更改。

--bash的意思是“登录shell”,但是是你需要考虑的是,在你测试值,或者希望将其展示给别人的地方。
Etan Reisner

0

由于情况(1)和(2)是通过在.bashrc和.profile中获取我的环境变量来解决的,所以真正的问题是“我为(3)和(4)提供这些相同变量的文件的名称是什么?

看起来问题的第3部分(如何将环境变量导入Unity桌面)在askubuntu上有答案。这里的建议是创建一个〜/ .xsessionrc文件,该文件将由/ etc / X11 / Xsession获取。(我已经尝试过了,它似乎可以工作...是的!)

我仍然对(4)的操作感到困惑。当然,如果创建了一个cron作业(或守护程序),我可以将'/ bin / foo'替换为'bash -i -c / bin / foo'之类的东西,以强制其使用bash加载正确的环境变量,但是这也意味着我将不得不修改可能代表我安装守护程序任务或cron作业的任何第三方工具。Yu

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.