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

Posted

技术标签:

【中文标题】通过 launchd.conf 设置环境变量不再适用于 OS X Yosemite/El Capitan/macOS Sierra/Mojave?【英文标题】:Setting environment variables via launchd.conf no longer works in OS X Yosemite/El Capitan/macOS Sierra/Mojave? 【发布时间】:2014-10-12 16:51:11 【问题描述】:

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

还有其他永久设置环境变量的解决方案吗?

【问题讨论】:

【参考方案1】:

~/Library/LaunchAgents/ 中创建一个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>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>

您可以在&lt;string&gt;&lt;/string&gt; 块内添加许多launchctl 命令。

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 user path ...' 和 /etc/paths 进行设置。

【讨论】:

无需重启!您可以执行“launchctl start environment.plist”并重新启动您需要获取新环境变量的应用程序;) 这不适用于我的 PATH 变量。因此,除了这种设置其他变量的方法外,我还在 ~/.bash_profile 中设置了 PATH 变量。这可能并不适用于所有情况,但到目前为止我还没有遇到问题。 想通了:要在不重新启动的情况下工作,它应该是“launchctl load environment.plist”,而不是 start 啊,是的。没有什么比在整个互联网上出现 9 次的晦涩配置设置更好的了 (google UseSanitizedBuildSystemEnvironment)。 也适用于 Sierra【参考方案2】:

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

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

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

do shell script "launchctl setenv variablename value"

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

现在将 (+s) 保存为文件格式:应用程序。最后打开 System SettingsUsers & GroupsLogin Items 并添加您的新应用程序。

[原始答案]:要解决您希望在简短的 shell 脚本中定义的所有变量,请查看此previous answer about how to run a script on MacOS login。这样当用户登录时脚本就会被调用。

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

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

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

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

【讨论】:

据我所知,这种技术的一个缺点是不会为登录时启动的任何其他应用程序设置变量。因此,例如,如果您打开终端,该变量将被设置,但如果您注销并重新登录,终端自动重启,该变量将被取消设置... 我已经尝试过这个解决方案,但它对我也不起作用。但我特别希望我的 Java IDE (IntelliJ) 能够接受我的路径修改,但事实并非如此。从终端一切正常。这可能是 IntelliJ 中的一个错误。仍然令人沮丧的是,Apple 删除了此功能。我给 Apple 打了电话,他们帮不上什么忙。 这对我有用,但是您知道如何将环境变量也添加到 sudo 吗? 这通常会起作用,但是在 Yosemite(至少 10.10.0 和 10.10.1)中有一个错误,设置 $PATH 不能以这种方式工作。苹果已经意识到了这个错误。目前(截至 10.10.1)没有已知的方法可以为 GUI 应用程序设置系统范围的 $PATH。 使用上述方法之一并重新启动笔记本电脑后 - 确保明确重新打开应用程序(例如 iTerm、终端、Eclipse、IDEA 或您正在使用的任何应用程序)。如果您没有明确地重新启动它们并且如果在重新启动 OSx 时复选框被选中“重新登录时重新启动窗口”(这是默认设置) - 这些程序将不会读取新的环境变量。【参考方案3】:

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

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

$ 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>

root 用户应用的相同服务定义:

$ 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

我们得到了什么:

    唯一声明系统环境变量的地方:/etc/environment 修改 /etc/environment 文件后即时自动更新环境变量 - 只需重新启动您的应用程序

问题/问题:

为了让应用程序在系统重启后正确获取您的环境变量,您需要:

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

发生这种情况是因为 Apple 拒绝对加载的服务进行显式排序,因此 env 变量与“重新打开队列”的处理并行注册。

但实际上,我每年只重启几次系统(在大更新时),所以这没什么大不了的。

【讨论】:

好主意。我已经尝试过了,它适用于大多数环境变量(如JAVA_HOME),但不适用于PATH 变量(见my question on ask different)。 PATH 应该使用 /etc/paths 文件设置。只需将您的自定义路径添加到此文件的末尾即可。 我对@9​​87654329@ 不是很熟悉,但是不能在启动时(即登录前)加载这些守护进程吗?这应该可以规避您提到的所有问题。 我喜欢上面的方法,但有一个奇怪的问题需要处理。重新启动后,genet VARNAME 返回了正确的值,但 echo $VARNAME 什么也不返回。这可能是什么原因?我也将其发布到***.com/questions/27045137/…,希望这里的任何人都有想法 确认/etc/environment的文件权限如前所述。【参考方案4】:

引用自

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

经过深思熟虑,工程部门已删除此功能。 出于安全原因,有意删除了文件 /etc/launchd.conf。 作为一种解决方法,您可以在引导期间尽早以 root 身份运行 launchctl limit,可能来自 LaunchDaemon。 (...)

解决方案:

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

#!/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

【讨论】:

你能再解释一下吗?我看不出“解决问题”与最初的问题有何关系! 不是OP,但我认为这里的要点是:将此plist放入/Library/LaunchDaemons,而不是告诉launchctl运行limit命令,告诉它运行@987654330带有PATH 和路径字符串作为参数的@ 命令。 launchd 应该会在启动时自动拾取它并几乎立即进行自我修改。 xml复制不完整。 doctype 行应为&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt; @aax plist 的哪一部分实际上设置了环境变量?【参考方案5】:

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

# 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

现在您可以在/etc/launchd.conf 中指定类似setenv JAVA_HOME /Library/Java/Home 的命令。

检查了 El Capitan。

【讨论】:

【参考方案6】:

什么对我有用(灵感来自 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>

如果你需要它一步一步:

启动终端 输入 sudo su 然后输入密码以 root 身份登录 键入 vi /Library/LaunchDaemons/com.apple.launchd.limit.plist 进入 vi 编辑器时,按 i 键进入插入模式,然后粘贴上面的确切代码内容 (⌘+v)。这将强制限制每个进程 16384 个文件,总共 16384 个文件 使用esc 保存文件并退出,然后使用:wq 重新启动系统,并使用命令 launchctl limit 检查它是否正常工作

希望对你有所帮助。

【讨论】:

这个方案和设置环境变量有什么关系?【参考方案7】:

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

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

我回答了一个类似的问题here,您可以在其中找到更多信息。

【讨论】:

【参考方案8】:

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

【讨论】:

将环境变量添加到配置文件非常差,因为它只影响 shell 进程。【参考方案9】:

我通过以下方式在 ~/.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。 另外,这种方法的问题是你仍然需要在环境变量可用之前打开终端。最好做第一个答案中的内容,以便无需打开终端即可使用它们。 这不适用于通过 SpotLight 加载的应用程序。 ***.com/questions/135688/… 使用 bash 配置文件的帮助有限,因为它假定您始终将 bash 作为您试图影响的环境的进程的祖先。 Spotlight、finder、emacs、xcode、cronjobs、launchd 代理、任何 IDE、源代码控制浏览器等,都不会以 bash 作为祖先。唯一可以持续跨越这些的进程是 launchd。

以上是关于通过 launchd.conf 设置环境变量不再适用于 OS X Yosemite/El Capitan/macOS Sierra/Mojave?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过环境变量设置 Java 的最小和最大堆大小?

控制台设置临时环境变量

centos7下设置opencv环境变量

通过修改注册表设置windows环境变量

普适计算的六大必备条件

不配置JDK环境变量,配置tomcat 指向启动JDK版本,不再依赖环境变量