设置环境变量的最佳发行版/与 shell 无关的方法是什么?

设置环境变量的最佳发行版/与 shell 无关的方法是什么?

这个问题说明了一切。我目前使用 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 somecommandssh 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_loginor~/.bash_profile如果它们存在而不是~/.profile.此外,~/.bashrc即使 bash 是交互式的,它也不会在登录 shell 中读取内容。为了永远不必再次记住这些怪癖,请~/.bash_profile使用以下两行创建一个:

. ~/.profile
case $- in *i*) . ~/.bashrc;; esac

也可以看看应该使用哪些设置文件来使用 bash 设置环境变量?

如果您的登录 shell 是 zsh

Zsh 读取~/.zprofileand ~/.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是否是不互动(!) 及其父进程称为rshdor 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

相关内容