我应该在哪里导出环境变量,以便 bash/dash、交互式/非交互式、登录/非登录的所有组合都可以选择它?

Mic*_*lot 11 linux bash ubuntu-12.04

这是问题的动机:

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

我想我可以更改所有这些快捷方式以使用 /bin/bash 而不是 /bin/sh 来强制它接受 .bashrc 更改,但这似乎真的很hacky。

鉴于 Ubuntu 12.04(默认情况下)将 /bin/sh 别名为 /bin/dash 并且我的默认 shell 是 /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 不会被读取。

(如果其他因素也很重要,例如 shell 是否是交互式的,我也不会感到惊讶,所以可能还有更多我没有预料到的组合......我很高兴我的问题“得到了改进” “ 在这种情况下。)

我希望在某个时候,一定有人制作了某种指南,告诉您如何/在何处以与 shell 无关的方式(或至少是与破折号/bash 兼容的方式)修改环境变量……我只能'似乎找不到正确的搜索词来定位这样的指南。

非常感谢解决方案或解决方案的指针!

更新:

  • 说明:这是 12.04 安装过程创建的默认 Ubuntu 用户,所以没什么特别的。它确实有一个 ~/.profile(明确来源 ~/.bashrc),并且唯一存在的 ~/.bash* 文件是 .bashrc、.bash_history 和 .bash_logout...所以没有 .bash_profile。
  • 强调范围:除了默认的交互式 shell (bash) 和任何碰巧使用 /bin/sh 的脚本(别名为破折号)之外,我并不真正关心任何 shell,所以没有必要用任何额外的东西来复杂化它tcsh/ksh/zsh/等。支持。

Eta*_*ner 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)
Run Code Online (Sandbox Code Playgroud)

——

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)
Run Code Online (Sandbox Code Playgroud)

我不知道其他贝壳,因为我从来没有使用过它们。您最好的选择可能是设置几个环境变量以指向公共位置脚本,并在未涵盖的几种情况下手动获取(在适当的情况下)。


小智 4

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

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#-}"
Run Code Online (Sandbox Code Playgroud)

然后使用如下所示的特定 shell 的命令(有些人更喜欢使用 case 语句)。

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

elif [ "$SHELLNAME" = 'ksh' ]
then
    stty erase ^?
fi
Run Code Online (Sandbox Code Playgroud)

如果我的命令只能在交互式 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
Run Code Online (Sandbox Code Playgroud)

例如,所有 sh 风格 shell 中常见的内容都PATH可以放在顶部。

然后,我使用符号链接在所有 sh 样式 shell 中加载相同的文件:

ln -s .profile .bashrc
ln -s .profile .kshrc
Run Code Online (Sandbox Code Playgroud)

一些旁注,如果您有一个.bash_profile,那么 bash 将加载它,而不是.profile但 dash 和 ksh 仍会加载.profile 这可能是您问题的一部分。

另外,您可能需要考虑#!/bin/bash在脚本中使用#!/bin/dash,除非您确实想要 POSIX 兼容脚本。bash 有很多非常好的额外功能,并且调用 dash 或 bash 因为 sh 会禁用其中许多功能。

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