这个问题说明了一切。我目前使用 Arch Linux 和 zsh,但我想要一个(至少)在 VT 和 xterms 上都能工作的解决方案,并且(希望,最好)在我切换发行版或 shell 时也能继续工作。
我在不同发行版的文档中听到过对这个问题截然不同的答案。 Ubuntu 说“使用 .pam_environment”。我认为在 Arch 中他们推荐的内容取决于你的 shell。目前我把所有东西都放进去。轮廓如果 shell 由于某种原因没有获取它(例如 bash,如果 .bash_profile 存在),我会通过手动获取它来覆盖它。但似乎必须有更好的方法。
答案1
不幸的是,没有完全可移植的位置来设置环境变量。最接近的两个文件是~/.profile
,这是传统位置,在许多设置中开箱即用,并且~/.pam_environment
,一种现代、常见但有限的替代方案。
放入什么~/.pam_environment
~/.pam_environment
所有使用的登录方法都会读取该文件聚丙烯酰胺并且启用了该文件。这涵盖了当今大多数 Linux 系统。
其主要优点~/.pam_environment
是(启用后)它会在用户 shell 启动之前读取,因此无论会话类型、登录 shell 和其他复杂性如何,它都可以正常工作。它甚至适用于非交互式登录,例如su -c somecommand
和ssh somecommand
。
的主要限制~/.pam_environment
是您只能在那里放置简单的赋值,而不能放置复杂的 shell 语法。该文件的语法如下。
- 文件是逐行解析的。
VAR=VALUE
每行必须采用VAR 由字母、数字和下划线组成的形式。另一种形式允许使用语法和特殊变量和VAR DEFAULT=value
来扩展环境变量。${VAR}
@{HOME}
@{SHELL}
#
开始注释,它不能出现在值中。- 如果 VALUE 被 包围
"
,则 VAR 将设置为引号之间的字符串。 \$
或\@
插入文字$
or@
,并且可以通过使用 转义换行符来分割长行\
。- 如果存在语法错误,例如没有
=
空格或未加引号的空格,则该变量将从环境中删除。
所以从好的方面来看,~/.pam_environment
它适用于多种情况。缺点是,您无法使用命令的输出(例如,测试目录或程序是否存在),并且某些字符(#"
、换行符)无法或难以放入值中。
放入什么~/.profile
该文件应具有可移植 (POSIX) sh 语法。[[ … ]]
如果您知道您的系统将这些 shell作为/bin/sh
.
该文件可以由自动化应用程序中的脚本读取,因此它不应调用产生任何输出或调用的程序exec
。如果您想在文本模式登录上执行此操作,请仅对交互式 shell 执行此操作。例子:
case $- in *i*)
# Display a message if I have new mail
if mail -e; then echo 'You have new mail'; fi
# If zsh is available, and this looks like a text-mode login, run zsh
case "`ps $PPID` " in
*" login "*)
if type zsh >/dev/null 2>/dev/null; then exec zsh; fi;;
esac
esac
/bin/sh
这是用作登录 shell 并切换到您最喜欢的 shell的示例。也可以看看当我的系统管理员拒绝让我更改它时,如何使用 bash 作为我的登录 shell
~/.profile
非图形登录时什么时候不读取?
不同的登录外壳读取不同的文件。
如果您的登录 shell 是 bash
Bash 读取~/.bash_login
or~/.bash_profile
如果它们存在而不是~/.profile
.此外,~/.bashrc
即使 bash 是交互式的,它也不会在登录 shell 中读取内容。为了永远不必再次记住这些怪癖,请~/.bash_profile
使用以下两行创建一个:
. ~/.profile
case $- in *i*) . ~/.bashrc;; esac
也可以看看应该使用哪些设置文件来使用 bash 设置环境变量?
如果您的登录 shell 是 zsh
Zsh 读取~/.zprofile
and ~/.zlogin
,但不是~/.profile
。 zsh 的语法与 sh 不同,但可以~/.profile
在 sh 模拟模式下读取。您可以将其用于您的~/.zprofile
:
emulate sh -c '. ~/.profile'
也可以看看Zsh 没有点击 ~/.profile
如果您的登录 shell 是其他 shell
/bin/sh
除了用作登录 shell 和仅将您最喜欢的 shell(例如 Fish)用作交互式 shell 之外,您无能为力。这就是我用 zsh 所做的。请参阅上面的从 调用另一个 shell 的示例~/.profile
。
远程命令
当不通过交互式 shell 调用远程命令时,并非所有 shell 都会读取启动文件。
ENV
如果您设法传递变量,Ksh 会读取该变量指定的文件。
Bash 读取~/.bashrc
是否是不互动(!) 及其父进程称为rshd
or sshd
。所以你可以开始你~/.bashrc
的
if [[ $- != *i* ]]; then
. ~/.profile
return
fi
Zsh 总是~/.zshenv
在启动时读取。请谨慎使用,因为 zsh 的每个实例都会读取它,即使它是您设置了其他变量的子 shell。如果 zsh 是您的登录 shell,并且您只想使用它来设置远程命令的变量,请使用防护:在 中设置一些变量~/.profile
,例如MY_ENVIRONMENT_HAS_BEEN_SET=yes
,并在读取之前检查此防护~/.profile
。
if [[ -z $MY_ENVIRONMENT_HAS_BEEN_SET ]]; then emulate sh -c '~/.profile'; fi
图形登录案例
许多发行版、显示管理器和桌面环境都安排运行~/.profile
,或者通过从启动脚本显式获取它,或者通过运行登录 shell。
不幸的是,没有通用的方法来处理~/.profile
未读取的发行版/DM/DE 组合。
如果您使用由 启动的传统会话~/.xsession
,那么您应该在此处设置环境变量;通过采购~/.profile
(即)来做到这一点. ~/.profile
。请注意,在某些设置中,桌面环境启动脚本将~/.profile
再次获取源。
答案2
据我所知,不存在如何设置环境变量的与发行版和 shell 无关的标准。
最常见和事实上的标准似乎是/etc/profile
和~/.profile
。第二个最常见的似乎是/etc/environment
和~/.pam_environment
。
在我看来,我找到的所有文档你也已经找到了。无论如何,我将它们列在这里供其他读者参考。
- Debian 推荐
/etc/profile
并且~/.profile
(关联)。 - Ubuntu 推荐
/etc/environment
和~/.pam_environment
(关联)。 - Arch Linux 除其他外
/etc/profile
还提到了/etc/environment
(关联)。
/etc/environment
奖励:质疑debian 中使用和/或滥用的文本(关联,最后更新 2008 年)。
答案3
如果你使用systemd 宿主,你应该能够使用homectl
为您的用户帐户设置环境变量,而不管您的 shell 是什么。以下命令以EDITOR
这种方式设置环境变量。
homectl update username --setenv=EDITOR=/usr/bin/vim
答案4
我添加了以下脚本 ~/bin/agnostic_setenv:
#!/bin/csh -f
set args = ($*)
if ($#args == 1) then
echo "export $args[1]="
exit 0
endif
if ($#args == 2) then
if ("$args[1]" =~ *csh*) then
echo "setenv $args[2]"
exit 0
else
echo "export $args[1]=$args[2]"
exit 0
endif
endif
echo "setenv $args[2] $args[3]"
在 ~/.perl-homedir 中我使用:
eval `${HOME}/bin/agnostic_setenv $shell PERL_HOMEDIR 0`
agnostic_unsetenv 的类似脚本:
#!/bin/csh -f
set args = ($*)
if ($#args == 1) then
echo "export $args[1]"
exit 0
endif
echo "unsetenv $args[2]"
exit 0