通过launchd.conf设置环境变量在OS X Yosemite / El Capitan / macOS Sierra / Mojave中不再起作用?


189

看起来launchd.conf不再加载我的环境变量。还有其他人注意到吗?

是否存在另一种永久设置环境变量的解决方案?


它确实可以工作,并且可以在应用程序中使用,但不能在终端中使用
Chang Zhao

Answers:


158

创建具有以下内容的environment.plist文件~/Library/LaunchAgents/

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>my.startup</string>
  <key>ProgramArguments</key>
  <array>
    <string>sh</string>
    <string>-c</string>
    <string>
    launchctl setenv PRODUCTS_PATH /Users/mortimer/Projects/my_products
    launchctl setenv ANDROID_NDK_HOME /Applications/android-ndk
    launchctl setenv PATH $PATH:/Applications/gradle/bin
    </string>

  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

您可以launchctl<string></string>块内添加许多命令。

plist系统重新启动后会激活。您也可以使用launchctl load ~/Library/LaunchAgents/environment.plist它立即启动。

[编辑]

同样的解决方案在El Capitan中也适用。

默认情况下,Xcode 7.0+不评估环境变量。可以使用以下命令启用旧行为:

defaults write com.apple.dt.Xcode UseSanitizedBuildSystemEnvironment -bool NO

[编辑]

在几种情况下,这不太起作用。如果重新启动计算机并选择“重新登录时重新打开窗口”,则重新打开的窗口可能看不到变量(可能在运行代理之前已将其打开)。另外,如果您通过ssh登录,则不会设置变量(因此您需要在〜/ .bash_profile中进行设置)。最后,这似乎对El Capitan和Sierra上的PATH无效。需要通过“ launchctl config用户路径...”和/ etc / paths进行设置。


20
无需重启!您可以执行“ launchctl start environment.plist”并重新启动您需要获取新环境变量的应用程序;)
hasvn 2014年

1
这对我来说不适合使用PATH变量。因此,除了这种用于设置其他变量的方法之外,我还在〜/ .bash_profile中设置了PATH变量。这可能并不适合所有情况,但到目前为止我还没有遇到任何问题。
djule5

6
弄清楚了:要在不重新启动的情况下工作,应该是“ launchctl load environment.plist”,而不要启动
Dave Hartnoll 2015年

2
是的。就像一个晦涩的配置设置一样,它在整个互联网(google UseSanitizedBuildSystemEnvironment)中仅显示9次。
Ohad Schneider

2
适用于塞拉利昂以及
Shwouchk

64

[ 原始答案 ]:您仍然可以使用launchctl setenv variablename value设置一个变量,以便所有应用程序(通过终端或通过Dock或Spotlight启动的图形应用程序)可以使用该变量。

显然,您每次登录都不希望这样做。

[ 编辑 ]:为避免这种情况,请启动AppleScript Editor,输入如下命令:

do shell script "launchctl setenv variablename value"

(如果要设置多个变量,请使用多行)

现在将(+ s)另存为文件格式:Application。最后打开System Settings用户和组登录项,然后添加新的应用程序。

[ 原始答案 ]:要变通解决此问题,请将所有希望定义的变量放在一个简短的Shell脚本中,然后查看有关如何在MacOS登录上运行脚本的先前答案。这样,当用户登录时将调用脚本。

[ 编辑 ]:两种解决方案都不完美,因为只能为该特定用户设置变量,但我希望/猜测这可能是您所需要的。

如果确实有多个用户,则可以为每个用户手动设置一个登录项,或者将com.user.loginscript.plist的副本放置在其每个本地Library / LaunchAgents目录中,指向同一外壳脚本。

当然,这些解决方法都不如/etc/launchd.conf方便。

[ 进一步编辑 ]:下面的用户提到这对他不起作用。但是,我已经在多台Yosemite机器上进行了测试,它确实对我有用。如果遇到问题,请记住,您需要重新启动应用程序才能使此操作生效。另外,如果您通过〜/ .profile〜/ .bash_profile在终端中设置变量,则它们将覆盖通过launchctl setenv从Shell启动应用程序设置的内容


5
据我所知,该技术的一个缺点是不会为登录时启动的任何其他应用程序设置变量。因此,例如,如果您打开Terminal,则将设置该变量,但如果注销并再次登录,而Terminal自动重启,则该变量将未设置...
JasonD 2014年

我已经尝试过这种解决方案,但对我也不起作用。但是我特别希望Java IDE(IntelliJ)可以修改我的路径,但事实并非如此。从终端一切正常。这可能是IntelliJ中的错误。仍然令人沮丧的是,苹果公司删除了此功能。我给苹果打电话了,他们的帮助不是很大。
杰森

这对我有用,但是您知道如何将环境变量也添加到sudo吗?
etiennenoel 2014年

2
通常,这可以正常工作,但是优胜美地(Yosemite)中存在一个错误(至少10.10.0和10.10.1),其中设置$ PATH不能以这种方式工作。苹果知道该错误。当前(从10.10.1开始),尚无已知方法为GUI应用程序设置系统范围的$ PATH。
TJ Luoma 2014年

3
使用上述方法之一并重新启动笔记本电脑后-确保您明确地重新打开应用程序(例如iTerm,终端,Eclipse,IDEA或正在使用的任何设备)。如果您没有明确重新启动它们,并且如果在重新启动OSx时选中了“重新登录时重新启动窗口”复选框(默认设置),则这些程序将不会读取新的环境变量。
2015年

21

可以使用3个文件+ 2个命令在Mac OS X 10.10 Yosemite上设置环境变量。

具有环境变量定义的主文件:

$ ls -la /etc/environment 
-r-xr-xr-x  1 root  wheel  369 Oct 21 04:42 /etc/environment
$ cat /etc/environment
#!/bin/sh

set -e

syslog -s -l warn "Set environment variables with /etc/environment $(whoami) - start"

launchctl setenv JAVA_HOME      /usr/local/jdk1.7
launchctl setenv MAVEN_HOME     /opt/local/share/java/maven3

if [ -x /usr/libexec/path_helper ]; then
    export PATH=""
    eval `/usr/libexec/path_helper -s`
    launchctl setenv PATH $PATH
fi

osascript -e 'tell app "Dock" to quit'

syslog -s -l warn "Set environment variables with /etc/environment $(whoami) - complete"

加载用户应用程序(终端,IDE等)的环境变量的服务定义:

$ ls -la /Library/LaunchAgents/environment.user.plist
-rw-------  1 root  wheel  504 Oct 21 04:37 /Library/LaunchAgents/environment.user.plist
$ sudo cat /Library/LaunchAgents/environment.user.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>environment.user</string>
    <key>ProgramArguments</key>
    <array>
            <string>/etc/environment</string>
    </array>
    <key>KeepAlive</key>
    <false/>
    <key>RunAtLoad</key>
    <true/>
    <key>WatchPaths</key>
    <array>
        <string>/etc/environment</string>
    </array>
</dict>
</plist>

根用户应用程序的服务定义相同:

$ ls -la /Library/LaunchDaemons/environment.plist
-rw-------  1 root  wheel  499 Oct 21 04:38 /Library/LaunchDaemons/environment.plist
$ sudo cat /Library/LaunchDaemons/environment.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>environment</string>
    <key>ProgramArguments</key>
    <array>
            <string>/etc/environment</string>
    </array>
    <key>KeepAlive</key>
    <false/>
    <key>RunAtLoad</key>
    <true/>
    <key>WatchPaths</key>
    <array>
        <string>/etc/environment</string>
    </array>
</dict>
</plist>

最后,我们应该注册以下服务:

$ launchctl load -w /Library/LaunchAgents/environment.user.plist
$ sudo launchctl load -w /Library/LaunchDaemons/environment.plist

我们得到的是:

  1. 声明系统环境变量的唯一位置:/ etc / environment
  2. 修改/ etc / environment文件后立即自动更新环境变量-只需重新启动您的应用程序

问题/问题:

为了在系统重新引导后应用程序正确地使用环境变量,您将需要:

  • 两次登录:登录=>注销=>登录
  • 或手动关闭并重新打开应用程序,应使用env变量
  • 或不要使用“重新登录时重新打开窗口”功能。

这是由于Apple拒绝加载服务的显式排序而导致的,因此env变量与“重新打开队列”的处理并行注册。

但是实际上,我每年仅重新启动系统几次(进行重大更新),所以这没什么大不了的。


好想法。我已经尝试过了,它适用于大多数环境变量(例如JAVA_HOME),但不适用于该PATH变量(请参阅有关ask different的问题)。
halloleo 2014年

4
PATH应该使用/ etc / paths文件设置。只需将自定义路径添加到此文件的末尾即可。
ursa 2014年

我不太熟悉launchd,但是在启动时(即登录之前)无法加载这些守护进程吗?那应该避开您提到的所有问题。
伊贡2014年

我喜欢上面的方法,但是有一个奇怪的问题要处理。重新启动后,genet VARNAME返回正确的值,但echo $ VARNAME不返回任何值。这可能是什么原因?我也将其发布到stackoverflow.com/questions/27045137/…,希望这里的任何人都有一个主意
ctp 2014年

确保/ etc / environment的文件许可权如上所述。
imanuelcostigan 2014年

6

引自

Apple Developer Relations 10-Oct-2014 09:12 PM

经过深思熟虑,工程技术已删除此功能。/etc/launchd.conf出于安全原因有意删除了该文件。解决方法是,您可以launchctl limit在引导过程中尽早以root身份运行,也许可以从LaunchDaemon。(...)

解:

/Library/LaunchDaemons/com.apple.launchd.limit.plist通过bash-script 将代码放入:

#!/bin/bash

echo '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>eicar</string>
        <key>ProgramArguments</key>
        <array>
                <string>/bin/launchctl</string>
                <string>limit</string>
                <string>core</string>
                <string>unlimited</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>ServiceIPC</key>
        <false/>
</dict>
</plist>' | sudo tee /Library/LaunchDaemons/com.apple.launchd.limit.plist

1
您能再解释一下吗?我看不到“解决问题”与最初的问题有何关系!
尼克H247 2014年

不是OP,而是我的要旨是:将此plist放入中/Library/LaunchDaemons,而不是告诉launchctl运行limit命令,而是告诉它运行并以路径字符串作为参数来运行setenv命令PATHlaunchd应该在启动时自动将其拾取并几乎立即进行自我修改。
尼尔森·尼尔森

5
xml复制不完整。doctype行应显示为<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
UloPe 2014年

6
@aax该plist的哪一部分实际上设置了环境变量?
HairOfTheDog

3

以下是恢复旧行为的命令:

# create a script that calls launchctl iterating through /etc/launchd.conf
echo '#!/bin/sh

while read line || [[ -n $line ]] ; do launchctl $line ; done < /etc/launchd.conf;
' > /usr/local/bin/launchd.conf.sh

# make it executable
chmod +x /usr/local/bin/launchd.conf.sh

# launch the script at startup
echo '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>launchd.conf</string>
  <key>ProgramArguments</key>
  <array>
    <string>sh</string>
    <string>-c</string>
    <string>/usr/local/bin/launchd.conf.sh</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>
' > /Library/LaunchAgents/launchd.conf.plist

现在,你可以像指定命令setenv JAVA_HOME /Library/Java/Home/etc/launchd.conf

在El Capitan上检查。


2

对我有用的是什么(受到aax的启发):

将此粘贴到/Library/LaunchDaemons/com.apple.launchd.limit.plist中,然后重新启动:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  <plist version="1.0">
  <dict>
  <key>Label</key>
  <string>eicar</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/launchctl</string>
    <string>limit</string>
    <string>maxfiles</string>
    <string>16384</string>
    <string>16384</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>ServiceIPC</key>
  <false/>
</dict>
</plist>

如果需要,请按以下步骤操作:

  • 启动终端
  • 类型须藤苏然后输入密码登录为根
  • 输入vi /Library/LaunchDaemons/com.apple.launchd.limit.plist
  • 进入vi编辑器后,按i键进入插入模式,然后将确切的代码内容粘贴到(⌘+v)上方。这将限制为每个进程16384个文件,总共16384个文件
  • 保存文件,esc然后使用退出:wq
  • 重新引导系统,并使用命令launchctl limit检查系统是否正常运行

希望对您有所帮助。


10
该解决方案与设置环境变量有什么关系?
HairOfTheDog

2

您可以尝试https://github.com/ersiner/osx-env-sync。它可以单一来源处理命令行和GUI应用程序,并且可以与最新版本的OS X(Yosemite)一起使用。

您可以使用路径替换和其他Shell技巧,因为您编写的是常规的bash脚本,该脚本首先由bash来提供。没有限制。.(查看osx-env-sync文档,您将了解它是如何实现的。)

在这里回答了类似的问题,您将其中找到更多信息。


-3

解决方法是将变量添加到中/etc/profile。然后一切都按预期工作!当然,您必须以sudo nano / etc / profile的root用户身份进行操作。如果以任何其他方式编辑它,即使将权限更改为root,系统也会抱怨/ etc / profile损坏。


7
将环境变量添加到配置文件中的效果非常差,因为它只会影响Shell进程。
2014年

-5

我通过以下方式在〜/ .bash_profile中添加了变量。完成后,重新启动/注销并登录

export M2_HOME=/Users/robin/softwares/apache-maven-3.2.3
export ANT_HOME=/Users/robin/softwares/apache-ant-1.9.4
launchctl setenv M2_HOME $M2_HOME
launchctl setenv ANT_HOME $ANT_HOME
export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Users/robin/softwares/apache-maven-3.2.3/bin:/Users/robin/softwares/apache-ant-1.9.4/bin
launchctl setenv PATH $PATH

注意:无需重新启动/注销和登录,您可以使用以下方法应用这些更改:

source ~/.bash_profile

请注意,您不必注销并重新登录。只需使用source命令,即source .bash_profile。
2015年

2
同样,此方法的问题在于,在环境变量可用之前,您仍然必须打开终端。最好做第一个答案中的内容,以便无需打开终端即可使用它们。
迈克尔

1
这不适用于通过SpotLight加载的应用。stackoverflow.com/questions/135688/...
Rasika佩雷拉

1
使用bash配置文件的帮助有限,因为它假定您一直是bash的始祖,而bash是您尝试实现环境的过程的始祖。Spotlight,finder,emacs,xcode,cronjobs,已启动的代理,任何IDE,源代码控制浏览器等,都不会以bash作为祖先。启动了可以始终如一地跨越这些范围的过程。
本·海德2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.