小心!坏.pam_environment文件可能会破坏您的登录。

小心!坏.pam_environment文件可能会破坏您的登录。

我的 shellzsh和操作系统是 Ubuntu 13.04

我需要将目录添加到 $PATH 才能使其在以下位置工作:

  • 在图形环境(Unity)中(例如启动应用程序、gmrun通过快捷方式运行的程序(基本上是 alt+f2 上的“运行命令”)
  • 在 Unity 终端中
  • 在终端上Ctrl++AltF1

我已经添加了它.profile,它适用于前两点,但不是最后一点。我知道我可能会添加它,.zshrc但在这种情况下,它将被写入两个地方(违反 DRY),并且在 unity 内部终端的情况下,它将被写入两次$PATH(我不认为这很糟糕,但至少不漂亮)

如果我仅将其添加到.zshrc它仅适用于第二种和第三种情况(显然)

我能做些什么?

答案1

为所有登录设置环境变量(无论类型)

最好的办法是使用~/.pam_environment例如,/opt/blah/bin在末尾添加PATH,你可以把这个放在.pam_environment你的主目录中的文件中:

PATH DEFAULT=${PATH}:/opt/blah/bin

全局设置环境变量(但除非必要,否则不要这样做)

如果你想添加一些PATH东西全部用户,而是使用/etc/environment。令人困惑的是,它们使用的语法并不相同。虽然它们实际上都不是脚本,但/etc/environment看起来像脚本(~/.pam_environment/etc/environment没有任何export命令)。因此,如果你想要添加/opt/blah/bin到每个人的末尾PATH,并且PATH/etc/environment开始为

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"

那么你可以将其更改为:

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/blah/bin"

分析

大多数 Bourne 风格的 shell(包括)在作为登录 shell 启动时bash都会执行 source 。是一个不寻常的例外;它仅在使用传统 Bourne 风格的 shell 之一的名称调用时才会执行此操作。也就是说,如果你~/.profilezsh称呼 zsh通过名称sh或(最常见的方法是使用其中一个名称ksh创建符号链接来实现),它将表现得像它们和源(如果它是登录 shell)。否则,它不会。(来源:zsh~/.profileman zsh

这就是zsh为什么虚拟控制台会话(例如,您转到Ctrl++Alt的位置F1)不会设置PATH环境变量~/.profile。它是一个登录 shell,但zsh很特殊;它的行为不像传统的 Bourne 风格 shell,除非它假装是这样的。

为什么zsh运行终端窗口时会显示你设置的环境变量~/.profile?因为在你启动终端之前,它们已经在你的图形会话中设置好了. 当您以图形方式登录时,显示管理器(提供图形登录屏幕并管理图形会话)充当登录 shell。通常它来源~/.profile(尽管它不是保证它会这样做,有时有人会更改桌面环境,却发现~/.profile当他们以图形方式登录时不再有来源)。

基于文本的虚拟控制台不会~/.profile不获取源代码。例如,如果您的 shell 是bash而不是zsh,并且您在虚拟控制台中登录,~/.profile则会获取源代码。问题是,与传统 Bourne 风格 shell 的可靠行为以及显示管理器启动图形登录会话的不太可靠的行为不同,当它是您的登录 shell 时zsh不会获取源代码~/.profile

类似地,在设置了环境变量的情况下~/.profile,如果您要远程登录(例如,通过启用 SSH 并以此方式登录),~/.profile则将无法获取来源。

/etc/profile顺便说一句,这也适用于全局文件。如果您在那里全局设置环境变量,您将遇到与在 中为用户设置环境变量相同的行为~/.profile

解决方案,假设您不需要编写脚本测试来确定环境变量的内容,是在 中设置用户特定的环境变量~/.pam_environment,并在 中设置系统范围(即所有用户)的环境变量/etc/environment

当你这样做的时候,聚丙烯酰胺(具体来说,pam_env.so)为每种类型的登录设置登录变量,并这样做登录 shell(例如,zsh对于bash大多数人来说)或类似登录 shell 的东西(例如,显示管理器)提供自己的登录配置文件。这是目前在 Ubuntu 上设置环境变量的一般推荐方法

~/.profile这种方式解决了一些登录 shell 并不总是提供和的问题/etc/profile(这是您遇到的问题)。它还解决了显示管理器在初始化图形登录会话时偶尔不提供该文件的问题(这是您遇到的问题不是经历)。

备择方案

如果什么:

  • 您需要根据脚本测试的结果在登录时设置环境变量吗?或者
  • 您只是不想使用.pam_environment(或者对于系统范围的变量,/etc/environment

如果您没有使用zsh,而是使用了bash或其他更传统的 Bourne 风格 shell,那么您只需在 中设置环境变量~/.profile(或/etc/profile设置系统范围的变量)。有时,在配置中,这不会为图形登录会话设置它们,但通常它可以工作。

将它们设置~/.bashrc 不适用于此目的。本质上仅bash提供该文件,因此当zsh您的登录 shell 或显示管理器充当您的登录 shell 时,它都不会起作用。(换句话说,在您的情形下,它根本无法工作。)

因此,如果您需要一个适用于所有类型的登录且~/.profile适用于图形会话的脚本,您可以简单地:

  • 修改zsh源的配置~/.profile或者
  • 制作两个zsh的配置并~/.profile获取第三个共享文件。(这甚至可以添加到图形会话的单独配置文件中,例如.xsession,如果以后有需要的话。)

and made sure they--and the contents of any script sourced from在这两个选项中,除非您已经阅读过 ~/.profile .profile zsh`的内容,否则第二个选项更好--won't cause problems if sourced by。(通常不应该,但你永远不知道。)

在登录时修改、制作zsh~/.profile(或其他脚本)的最佳配置文件是~/.zprofile。这对应于~/.profile更传统的 Bourne 风格 shell。(严格来说,它是$ZDOTDIR/.zprofile,但$ZDOTDIR通常是~。)

您需要将该行添加source $HOME/.profile到该文件中。

不过,我强调一下,如果只需要对环境变量执行简单的赋值(包括递归赋值,其中环境变量被分配一个包含其自身和/或其他环境变量的表达式),你应该使用~/.pam_environment如上所述(或/etc/environment针对系统范围的环境变量)。

答案2

首先,您只需在 .zshrc 文件中获取 .profile 即可。

除此之外,当您使用 zsh 时,您可以将以下内容添加到 .zshrc 中:

typeset -U path

# If you want it at the front of your path
path=({/custom/path/bin "${path[@]}")

# If you want it at the end of your path
path+=(/custom/path/bin)

工作原理:

在 zsh 中,$PATH变量绑定到$path变量;$path是一个数组,并且$PATH是一个标量,其中的元素$path由 连接:(与 相同${(j|:|)path})。typeset -U path使得数组的元素path(以及$PATH)是唯一的。

   typeset [ {+|-}AEFHUafghklprtuxmz ] [ -LRZi [ n ]] [ name[=value] ... ]
   typeset -T [ {+|-}Urux ] [ -LRZ [ n ]] SCALAR[=value] array [ sep ]
          Set or display attributes and values for shell parameters.
          (...)
          -U     For  arrays  (but  not for associative arrays), keep only
                 the first occurrence of each duplicated value.  This  may
                 also  be  set for colon-separated special parameters like
                 PATH or FIGNORE, etc.  This flag has a different  meaning
                 when used with -f; see below.

答案3

这个答案基本上基于 Eliah Kagan 的答案,包含了我真正做的事情。

我已经添加到~/.pam_environment

PATH DEFAULT=${PATH}:/home/riad/scripts

但至少在我的 PC 上,它不是在 tty1 (++) 登录时解析的,Ctrl而是在图形登录时解析的。(即使是由 unity 创建的语言环境设置在非图形登录中也不起作用)AltF1

原因是 lightdm 的 pam 配置文件中有以下行(/etc/pam.d/lightdm):

session required        pam_env.so readenv=1 user_readenv=1 envfile=/etc/default/locale

我在/etc/pam.d/login之间添加了相同的行

@include common-session

@include common-password

小心!坏.pam_environment文件可能会破坏您的登录。

相关内容