Mac环境变量释疑

PATH Environment Variable On Mac OS X & Emacs.App 

分类: emacs   1118人阅读  评论(0)  收藏  举报

目录(?)[+]

From: http://blog.galeo.me/post/23467503436/path-environment-variable-on-mac-os-x-emacs-app

有几次朋友问我晚上的时候在干什么,我开玩笑似地说我在“磨刀”,他或许一下子不解了——我把折腾Emacs当做是磨刀。呵呵,“刀是不能不磨的”……长话短说,本文将介绍Mac OS X和GNU Emacs中的PATH环境变量及其设置方法。

首先你可能需要先了解一下Emacs For Mac OS。在Mac上,可能很多人偏爱Aquamacs这个发行版,相比较GNU Emacs(Cocoa),它是标准的OS X应用,而且针对Mac系统做了很多的优化和配置,让你使用起来得心应手,非常方便。但是,可能因为我当年第一次接触Emacs遇到的就是GNU Emacs(Cocoa),到后来再接触了Aquamacs,感觉Aquamacs看起来很不顺眼,而且这种感觉到今天也没有消失掉,我一如既往地对GNU Emacs钟情1

1 问题来源

很多 *nix 用户对于用户根目录下面同时出现的 .bash_profile .bashrc .bash_login .profile 这几个文件的作用和区别感到迷惑不解,当你想要把一个目录添加进PATH环境变量的时候,可能会不清楚选择哪个文件来操作。当你了解清楚了它们的差异并且明白了它们发生作用的原理之后,回过头来,又要处理Mac OS与传统 *nix 系统的不同2

Mac OS X中的Emacs.app3并不像在其他OS上那样或者像运行在Terminal以及Emacs中的shell,“简单地”继承系统的PATH环境变量,这就需要你额外进行设置。

2 Shell Configuration

在类UNIX系统中,你可以通过编辑相应shell启动时执行的 “startup” 文件来自定义shell程序的初始化工作。这些文件一般会被称为 “dot files” ,因为它们的名字经常是以 “dot(.)” 开始。用户自己的 “dot files” 一般都位于用户的根目录(User’s Home folder)4下面,需要你自己使用一个文本编辑器(e.g. vim, nano, emacs etc.)来创建。因为它们的名字都是以dot(.) 开始的,当你执行 “ls” 时,它们不会被显示,你需要使用 “-a” 参数: “ls -a” 来查看所有文件。如果你只需要列出以 “dot(.)” 开始的文件,可以使用命令 “ls -ld .*” 。

Shell startup文件当中经常包含下面一些设置:

  • shell execution PATH (determines where the shell will look for executables)
  • MANPATH (determines where the ‘man’ program will look for man pages)
  • shell aliases and functions (used to save you typing)
  • shell prompts
  • other environment variables

至于哪些初始文件会被shell启动时所读取取决于shell类型(e.g bash tcsh etc.)以及其是 login shell 还是 non-login shell 。5

2.1 Login Shell and Non-Login Shell

这里我们简单翻译为登录shell和非登录shell,至于为什么称呼 login shell ,是由于历史原因,当用户启动到文本模式的UNIX系统,输入用户口令登录后,shell便会启动。另外, login shell 也指使用 --login 参数启动的shell(bash --login)。以bash为例,下面的引用来自其man page6:

A login shell is one whose first character of argument zero is a -, or one started with the –login option.

对于bash,当一个登录shell启动时,它将按照下面的顺序读取初始化文件:

  1. /etc/profile
  2. ~/.bash_profile
  3. ~/.bash_login
  4. ~/.profile

首先如果 /etc/profile 文件存在,那么登录shell将首先读取它并且执行其中的命令,然后按照顺序搜索~/.bash_profile ~/.bash_login ~/.profile ,并且只读取执行其中的一个。

当一个非登录shell以交互方式启动时,将会读取 /etc/bashrc ,然后寻找并尝试读取执行 ~/.bashrc 。7

在Mac OS X中,你在Terminal程序中开启的shell都是登录shell,而当你打开一个xterm(在苹果的X11下)窗口时,你得到的则是非登录shell,这是Terminal和xterm在读取初始化文件方面的主要区别。

2.2 Maintain Shell Startup Files

更多时候,你不想为登录shell和非登录shell同时维护两个配置文件,比如当你改变PATH环境变量的时候,你可能会希望同时应用于两种shell。通过source命令来做到这点。比如,将PATH和其他设置都放到 .bashrc 里面,再让.bash_profile “引用” .bashrc ,只需要在 .bash_profile 中添加下面的代码:

<span style="color: rgb(237, 128, 73);">if</span> [ -f ~/.bashrc ]; <span style="color: rgb(237, 128, 73);">then</span>
   <span style="color: rgb(18, 174, 177);">source</span> ~/.bashrc
<span style="color: rgb(237, 128, 73);">fi</span>

这样,当开启一个登录shell的时候, .bashrc 会被读取并执行,你在其中所作的设置将会生效。

3 Mac OS X Runtime Configuration

Mac OS X中,程序运行分为两种,一种是使用终端(console),一种是使用GUI(图形用户界面),环境变量的设置需要根据不同的程序运行情况来分别设置。

当你打开Terminal.app,默认你将启动一个 bash shell 8,它将像上文介绍到的那样读取初始化文件。

我们知道,一般系统级的环境变量包括PATH会在 /etc/profile 中设置,当 bash 启动的时候会被读取。在Mac OS X中, /etc/profile 会使用path_helper来设置PATH9:

<span style="color: rgb(237, 128, 73);">if</span> [ -x /usr/libexec/path_helper ]; <span style="color: rgb(237, 128, 73);">then</span>
    <span style="color: rgb(18, 174, 177);">eval</span> <span style="color: rgb(250, 128, 114);">`/usr/libexec/path_helper -s`</span>
<span style="color: rgb(237, 128, 73);">fi</span>

path_helper 会读取 /etc/paths.d 和 /etc/manpaths.d 目录下的文件内容,将它们添加进相应的 PATH 和MANPATH 环境变量,这些目录下的文件一般通过单独的一行来指定一个路径。在读取这些目录之前,默认的 PATH 和MANPATH 的值会从文件 /etc/paths 和 /etc/manpaths 中获得。

OS X中的窗口程序则会从用户自己的 environment.plist 文件中获得环境变量,可以参考这里。文件~/.MacOSX/environment.plist 会由Xcode创建,如果你没有安装Xcode的话,可能需要手动创建(注意大小写敏感),之后你便可以通过Property List Editor10来编辑此文件,修改或者保存键值对。 environment.plist 可以被窗口程序包括Terminal使用来获得系统的各种环境变量,而你在 .bash_profile 或其他dot文件中做的设置将只会作用于bash或相应的shell。defaults11程序允许对此文件进行读写12,比如当你修改了enviroment.plist文件,并使当前shell使用其中PATH 的值,可以这样:

<span style="color: rgb(237, 128, 73);"># </span><span style="color: rgb(119, 197, 93);">bash</span>
<span style="color: rgb(18, 174, 177);">export</span> <span style="color: rgb(192, 135, 229);">PATH</span>=$(<span style="color: rgb(250, 128, 114);">defaults</span> read <span style="color: rgb(234, 79, 131);">"${HOME}/.MacOSX/environment"</span> PATH)

<span style="color: rgb(237, 128, 73);"># </span><span style="color: rgb(119, 197, 93);">tcsh</span>
<span style="color: rgb(18, 174, 177);">set</span> <span style="color: rgb(192, 135, 229);">path</span>=(<span style="color: rgb(250, 128, 114);">`defaults read ~/.MacOSX/environment PATH | tr ':' ' '`</span>)

如果你希望 /etc/profile 中将通过 path_helper 获取的PATH路径的值自动更新到 environment.plist 中去,可以在 /etc/profile 做下面的改动:

<span style="color: rgb(237, 128, 73);">#</span><span style="color: rgb(119, 197, 93);">/etc/profile begin</span>
<span style="color: rgb(237, 128, 73);">if</span> [ -x /usr/libexec/path_helper ]; <span style="color: rgb(237, 128, 73);">then</span>
    <span style="color: rgb(18, 174, 177);">eval</span> <span style="color: rgb(250, 128, 114);">`/usr/libexec/path_helper -s`</span>
    defaults write $<span style="color: rgb(192, 135, 229);">HOME</span>/.MacOSX/environment PATH <span style="color: rgb(234, 79, 131);">"$PATH"</span>
<span style="color: rgb(237, 128, 73);">fi</span>

一般情况下,你只需要在 .bash_profile 中设置环境变量而不需要改动 .plist 文件。大多数的Mac OS X窗口程序都不需要任何自定义的环境变量,只在程序实际需要一个特定的环境变量的时候,你才可能有必要修改environment.plist。

4 Emacs.App Set PATH

首先,根据上文的一系列介绍,我们可以得到关于Emacs如何从OS X中继承环境变量的三点总结:

  • 当你从shell中启动emacs的时候,emacs将继承shell的环境变量13
  • 当你以GUI方式直接启动Emacs.app,emacs将不会从shell那里继承环境变量,而是从~/.MacOSX/environment.plist 继承。
  • 当你从shell中以GUI方式启动emacs14,emacs也会继承shell的环境变量。

下面将介绍如何为Emacs设置 PATH 。

4.1 Setting PATH within Emacs

你可以直接为Emacs设置PATH环境变量,而不用以在OS中设置再让Emacs继承的方式。

使用命令 (getenv "PATH") 将会得到PATH环境变量的值,而 (setenv "PATH" VALUE) 用来将 PATH 设置为指定的字符串。如果你安装了MacPorts,想将其可执行文件目录添加进Emacs的PATH环境变量,可以在 .emacs 中添加下面的代码:

<span style="color: rgb(105, 105, 105);">(</span>setenv <span style="color: rgb(234, 79, 131);">"PATH"</span>
        <span style="color: rgb(105, 105, 105);">(</span>concat
         <span style="color: rgb(105, 105, 105);">(</span>getenv <span style="color: rgb(234, 79, 131);">"PATH"</span><span style="color: rgb(105, 105, 105);">)</span>
         <span style="color: rgb(234, 79, 131);">":""/opt/local/bin"</span>
         <span style="color: rgb(234, 79, 131);">":""/opt/local/sbin"</span><span style="color: rgb(105, 105, 105);">))</span>

4.2 Emacs’s exec-path

Emacs拥有一个 exec-path 变量,其值是一个文件目录的列表,当需要在子进程中运行程序的时候,Emacs会通过exec-path 来寻找可执行文件(e.g ispell or aspell, diff, grep, shell etc.) 。如果Emacs警告说它无法找到找到 ispell aspell gzip 等可执行文件,可能就是 exex-path 变量的问题。

默认,Emacs会将 (getenv "PATH") 的值赋给 exec-path ,所以 PATH 和 exec-path 的值会一致。但是二者之间又有区别:

  • PATH 的值被Emacs使用如果你在Emacs中开启一个shell(类似于你在终端中运行shell),或者当Emacs调用一些外部命令时(比如通过 M-x compile 执行编译)。
  • exec-path 被Emacs自身使用用来寻找可执行文件当你需要使用它的某些特性的时候,例如拼写检查,diff等。

当你需要在Emacs中设置 PATH 时,你可能也想一起调整 exec-path ,比如你想要设置使emacs直接从shell那里得到PATH 的值,并且设置 exec-path ,可以将下面的代码添加到 .emacs:

<span style="color: rgb(105, 105, 105);">(</span>setq *is-a-mac* <span style="color: rgb(105, 105, 105);">(</span>eq system-type 'darwin<span style="color: rgb(105, 105, 105);">))</span>

<span style="color: rgb(105, 105, 105);">(</span><span style="color: rgb(237, 128, 73);">defun</span> <span style="color: rgb(93, 195, 248);"><strong>string-rtrim</strong></span> <span style="color: rgb(105, 105, 105);">(</span>str<span style="color: rgb(105, 105, 105);">)</span>
  <span style="color: rgb(234, 79, 131);">"Remove trailing white-space from a string."</span>
  <span style="color: rgb(105, 105, 105);">(</span>replace-regexp-in-string <span style="color: rgb(234, 79, 131);">"[ \t\n]*$"</span> <span style="color: rgb(234, 79, 131);">""</span> str<span style="color: rgb(105, 105, 105);">))</span>

<span style="color: rgb(105, 105, 105);">(</span><span style="color: rgb(237, 128, 73);">defun</span> <span style="color: rgb(93, 195, 248);"><strong>set-exec-path-from-shell-PATH</strong></span> <span style="color: rgb(105, 105, 105);">()</span>
  <span style="color: rgb(105, 105, 105);">(</span>interactive<span style="color: rgb(105, 105, 105);">)</span>
  <span style="color: rgb(105, 105, 105);">(</span><span style="color: rgb(237, 128, 73);">let</span> <span style="color: rgb(105, 105, 105);">((</span>path-from-shell
         <span style="color: rgb(105, 105, 105);">(</span>string-rtrim
          <span style="color: rgb(105, 105, 105);">(</span>shell-command-to-string <span style="color: rgb(234, 79, 131);">"$SHELL --login -i -c 'echo $PATH'"</span><span style="color: rgb(105, 105, 105);">))))</span>
    <span style="color: rgb(105, 105, 105);">(</span>setenv <span style="color: rgb(234, 79, 131);">"PATH"</span> path-from-shell<span style="color: rgb(105, 105, 105);">)</span>
    <span style="color: rgb(105, 105, 105);">(</span>setq exec-path
          <span style="color: rgb(105, 105, 105);">(</span>split-string path-from-shell path-separator<span style="color: rgb(105, 105, 105);">))))</span>

<span style="color: rgb(105, 105, 105);">(</span><span style="color: rgb(237, 128, 73);">when</span> <span style="color: rgb(105, 105, 105);">(</span>and *is-a-mac* window-system<span style="color: rgb(105, 105, 105);">)</span>
  <span style="color: rgb(105, 105, 105);">(</span>set-exec-path-from-shell-PATH<span style="color: rgb(105, 105, 105);">))</span>

4.3 PATH in Emacs shell mode

在Emacs中,当你通过 M-x shell 开启一个shell,比如你设定了 shell-file-name 的值为”/bin/bash”,以使Emacs开启bash shell,这时候,bash是一个非登录shell,所以它会在用户根目录下寻找 .bashrc 来进行初始化,你可能需要将一些自定义的设置放到 .bashrc 中。上文中我们提到,这个shell还会继承Emacs中设置的 PATH ,这样就可能使 PATH 中出现重复的目录,比如为了简化维护,你的 .bashrc 中可能仅仅是下面一行内容:

<span style="color: rgb(18, 174, 177);">source</span> ~/.profile

而你在 .emacs 中像这样设置 PATH :

<span style="color: rgb(105, 105, 105);">(</span>setenv <span style="color: rgb(234, 79, 131);">"PATH"</span>
         <span style="color: rgb(105, 105, 105);">(</span>shell-command-to-string <span style="color: rgb(234, 79, 131);">"source $HOME/.profile && printf $PATH"</span><span style="color: rgb(105, 105, 105);">))</span>

然后,你用 echo $PATH 来查看 PATH 的值会发现其中很多目录是重复的,让人很不爽。你可以在 .profile 中编写一个函数用来将一个目录添加进 PATH 当且仅当这个目录不在当前的 PATH 中来消除一些重复,或者在 .bashrc 中复制 .profile 的内容,但是去掉相关的 PATH 设置。到目前为止,我还没有找到更好的方法。

5 Author’s Words

本文很多内容参考了 EmacsWiki 、 StackOverFlow.com 和 Apple 开发文档的相关主题,以及purcell的emacs设置中的相关内容,相应版权归其所有。 转载请注明来源网址: http://blog.galeo.me/post/23467503436/path-environment-variable-on-mac-os-x-emacs-app

Footnotes:

1 Emacs 24.1马上就要来了,好期待。后面我可能会写一篇文章,介绍Lisp的词法变量和动态变量,因为elisp在Emacs 24.1版本开始支持词法变量,所以可能顺带着介绍一下Emacs 24.1版本的某些变化。

2 虽然Mac OS X经过的UNIX认证,但是一些你在 *nix 中习以为常的东西到了OS X里面需要换个脑筋,”Think Different”,然后你会发现OS X在很多方面领先业界。

3 GNU Emacs在Mac OS X上的发行版,详细请参考上文中的链接。

4 用 “” 来表示(designated by )。

5 注意:在命令提示符之后输入shell名称(e.g bash tcsh),将会开启一个子shell(sub-shell),子shell将会继承父shell(parent shell)的环境变量,即使通过 --noprofile 参数来禁止shell读取初始化文件。

6 使用命令’man bash’。同样的,可以使用命令’man tcsh’查看tcsh的man page。

7 更多shell启动的细节,请参考man page。

8 可以在 Terminal -> Preferences 里面设置shell启动路径。

9 注意: path_helper 只能通过shell文件来使用,而不能直接手动调用。

10 Property List Editor comes as part of Apple’s Developer Tools Xcode 3 package, as of Xcode 4 on Lion, Apple no longer supplies it with its developer tools,不过你可以直接使用Xcode来编辑.plist文件。如果想要在Lion中继续使用Property List Editor,请参考这里,当然还有其他的选择,比如免费的Pref Setter,或者收费的PlistEdit Pro

11 In Terminal, type ‘man defaults’ for details.

12 注意:当你改动了environment.plist文件之后,你需要重启系统来生效。

13 这一点对于Windows,Linux,Mac均适用。

14 Like this: “nohup /Applications/Emacs.app/Contents/MacOS/Emacs &”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值