将目录添加到 $PATH 而不重复自己

Ria*_*iaD 6 startup unity zsh environment-variables 13.04

我的外壳是zsh,操作系统是 Ubuntu 13.04

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

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

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

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

我能做什么?

Eli*_*gan 5

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

最好的方法是使用~/.pam_environment. 例如,要添加/opt/blah/bin到 的末尾,您PATH可以将其放在.pam_environment主目录中的文件中:

PATH DEFAULT=${PATH}:/opt/blah/bin
Run Code Online (Sandbox Code Playgroud)

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

如果您想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"
Run Code Online (Sandbox Code Playgroud)

那么你可以把它改成:

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/blah/bin"
Run Code Online (Sandbox Code Playgroud)

分析

大多数 Bourne 风格的 shell,包括bash,将~/.profile在它们作为登录 shell 启动时获取。zsh是一个不寻常的例外;只有在使用传统 Bourne 风格 shell 之一的名称调用它时,它才会执行此操作。也就是说,如果您通过名称或(最常见的是通过使用这些名称之一创建符号链接来实现)调用 ,它将像它们和源一样运行(如果它是登录外壳)。否则,它不会。(来源:。)zshshkshzsh~/.profileman zsh

这就是为什么zsh虚拟控制台会话(例如,你去哪里Ctrl+ Alt+ F1)不设置PATH从环境变量~/.profile。它是一个登录shell,但zsh很特别;它的行为不像传统的 Bourne-style shell,除非它假装是一个。

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

没有关于基于文本的虚拟控制台的任何内容都~/.profile无法获取资源。例如,如果您的 shell 被bash代替zsh并且您在虚拟控制台中登录,~/.profile则将获得源。问题是,与传统 Bourne 风格的 shell 的可靠行为不同,以及启动图形登录会话的显示管理器的行为不太可靠,当它是您的登录 shell 时,zsh它不会来源~/.profile

类似地,在 中设置环境变量时~/.profile,如果您要远程登录(例如,通过启用 SSH 并以这种方式登录),则~/.profile不会获得源。

/etc/profile顺便说一下,这也适用于全局文件。如果您在那里全局设置环境变量,您会遇到与在~/.profile.

如果您不需要编写脚本测试来确定环境变量的内容,解决方案是~/.pam_environment/etc/environment.

当你这样做,PAM(特别是pam_env.so)设置变量上登录时,基本上每一种类型的登录,并且这样做之前登录shell(例如zshbash对于大多数人来说),或登录壳状的东西(例如,显示器manager) 提供自己的登录配置文件。这是目前普遍推荐的在 Ubuntu 上设置环境变量的方法

这种方式解决了一些登录 shell 并不总是采购~/.profile/etc/profile(这是您遇到的问题)的问题。它还解决了显示管理器在初始化图形登录会话时不获取该文件的偶然问题(这是您没有遇到的问题)。

备择方案

如果:

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

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

设置它们~/.bashrc 不会用于此目的。本质上仅提供bash该文件的来源,因此它既不会在zsh您的登录 shell 出现时也不会在显示管理器充当您的登录 shell 时工作。(换句话说,在你的情况下,根本就行不通。)

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

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

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

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

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

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


Ria*_*iaD 1

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

我已经添加到~/.pam_environment

PATH DEFAULT=${PATH}:/home/riad/scripts
Run Code Online (Sandbox Code Playgroud)

但至少在我的电脑上,它没有在 tty1 (++) 登录上解析,Ctrl而是在图形登录上解析。(即使是由 unity 创建的区域设置在非图形登录中也不起作用)AltF1

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

session required        pam_env.so readenv=1 user_readenv=1 envfile=/etc/default/locale
Run Code Online (Sandbox Code Playgroud)

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

@include common-session
Run Code Online (Sandbox Code Playgroud)

@include common-password
Run Code Online (Sandbox Code Playgroud)

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