Ustawienie zmiennych środowiskowych za pomocą launchd.conf nie działa już w OS X Yosemite / El Capitan / macOS Sierra / Mojave?

190

Wygląda na launchd.confto, że nie ładuje już mojej zmiennej środowiskowej. Czy ktoś to zauważył?

Czy istnieje inne rozwiązanie, aby trwale ustawić zmienne środowiskowe?

Bzdury
źródło
Działa i udostępnia się w aplikacji, ale nie w terminalu
Chang Zhao,

Odpowiedzi:

159

Utwórz environment.plistplik w ~/Library/LaunchAgents/tej treści:

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

Możesz dodać wiele launchctlpoleceń wewnątrz <string></string>bloku.

plistUaktywni po ponownym uruchomieniu systemu. Możesz także użyć launchctl load ~/Library/LaunchAgents/environment.plistgo do natychmiastowego uruchomienia.

[Edytować]

To samo rozwiązanie działa również w El Capitan.

Xcode 7.0+ domyślnie nie ocenia zmiennych środowiskowych. Stare zachowanie można włączyć za pomocą tego polecenia:

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

[Edytować]

Jest kilka sytuacji, w których to nie do końca działa. Jeśli komputer zostanie zrestartowany i zostanie wybrana opcja „Ponownie otwórz okna podczas ponownego logowania”, ponownie otwarte okna mogą nie widzieć zmiennych (być może są one otwarte przed uruchomieniem agenta). Ponadto, jeśli zalogujesz się przez ssh, zmienne nie zostaną ustawione (więc musisz ustawić je w ~ / .bash_profile). Wreszcie, wydaje się, że nie działa to w przypadku PATH w El Capitan i Sierra. Należy to ustawić za pomocą „ścieżka użytkownika config Launctl ...” oraz w / etc / paths.

MortimerGoro
źródło
20
Nie ma potrzeby ponownego uruchamiania! Możesz zrobić „launchctl start environment.plist” i zrestartować aplikację, aby uzyskać nowe
zmienne
1
Nie działałoby to dla mnie ze zmienną PATH. Oprócz tego podejścia do ustawiania innych zmiennych, ustawiam zmienną PATH w moim ~ / .bash_profile. To może nie działać w każdym przypadku, ale jak dotąd nie mam problemu.
djule5
6
Zrozumiałem: Aby działać bez restartu, powinien to być „launchctl load environment.plist”, a nie start
Dave Hartnoll
2
O tak. Nie ma to jak niejasne ustawienie konfiguracji, które pojawia się dokładnie 9 razy w całym Internecie (google UseSanitizedBuildSystemEnvironment).
Ohad Schneider,
2
Działa również na Sierra
Shwouchk,
64

[ Oryginalna odpowiedź ]: Nadal można użyć launchctl setenv variablename valuedo ustawienia zmiennej, która będzie pobierana przez wszystkie aplikacje (aplikacje graficzne uruchamiane przez Dock lub Spotlight, oprócz tych uruchamianych przez terminal).

Oczywiście nie będziesz chciał tego robić przy każdym logowaniu.

[ Edytuj ]: Aby tego uniknąć, uruchom AppleScript Editor, wprowadź polecenie takie jak to:

do shell script "launchctl setenv variablename value"

(Użyj wielu linii, jeśli chcesz ustawić wiele zmiennych)

Teraz zapisz ( + s) jako Format pliku: Aplikacja . Na koniec otwórz System SettingsUżytkownicy i grupyZaloguj się i dodaj nową aplikację.

[ Oryginalna odpowiedź ]: Aby obejść to miejsce, wszystkie zmienne, które chcesz zdefiniować w skrypcie krótkiej powłoki, zapoznaj się z poprzednią odpowiedzią na temat uruchamiania skryptu przy logowaniu do MacOS . W ten sposób skrypt zostanie wywołany, gdy użytkownik się zaloguje.

[ Edytuj ]: Żadne z tych rozwiązań nie jest idealne, ponieważ zmienne zostaną ustawione tylko dla tego konkretnego użytkownika, ale mam nadzieję / zgaduję, że może być wszystkim, czego potrzebujesz.

Jeśli masz wielu użytkowników, możesz ręcznie ustawić element logowania dla każdego z nich lub umieścić kopię com.user.loginscript.plist w każdym z lokalnych katalogów Library / LaunchAgents , wskazując ten sam skrypt powłoki.

Oczywiście żadne z tych obejść nie jest tak wygodne jak /etc/launchd.conf .

[ Dalsza edycja ]: Użytkownik poniżej wspomina, że ​​to nie działało dla niego. Jednak przetestowałem na wielu maszynach Yosemite i to działa dla mnie. Jeśli masz problem, pamiętaj, że musisz ponownie uruchomić aplikacje, aby to zadziałało. Dodatkowo, jeśli ustawisz zmienne w terminalu za pomocą ~ / .profile lub ~ / .bash_profile , zastąpią one rzeczy ustawione przez launchctl setenv dla aplikacji uruchamianych z powłoki .

ruario
źródło
5
O ile mogę stwierdzić, jedną wadą tej techniki jest to, że zmienne nie zostaną ustawione dla innych aplikacji uruchomionych przy logowaniu. Na przykład, jeśli otworzysz Terminal, zmienna zostanie ustawiona, ale jeśli wylogujesz się i ponownie zalogujesz, a Terminal automatycznie się zrestartuje, zmienna nie zostanie ustawiona ...
JasonD,
Wypróbowałem to rozwiązanie i dla mnie też nie zadziałało. Ale szczególnie oczekuję, że mój Java IDE (IntelliJ) przejmie moje modyfikacje ścieżki i tak nie jest. Wszystko działa dobrze z terminala. Może to być błąd w IntelliJ. Nadal frustrujące jest to, że Apple usunął tę funkcję. Zadzwoniłem do Apple i nie byli bardzo pomocni.
Jason
To działa dla mnie, ale czy wiesz, co zrobić, aby dodać zmienne środowiskowe do sudo?
etiennenoel,
2
Będzie to ogólnie działać, jednak w Yosemite występuje błąd (przynajmniej 10.10.0 i 10.10.1), w którym ustawienie $ PATH nie działa w ten sposób. Apple jest świadomy błędu. Obecnie (od 10.10.1) nie ma znanego sposobu ustawiania systemowej ścieżki $ PATH dla aplikacji GUI.
TJ Luoma,
3
Po użyciu jednej z wyżej wymienionych metod i ponownym uruchomieniu laptopa - upewnij się, że ponownie otworzyłeś aplikacje (takie jak iTerm, terminal, Eclipse, IDEA lub cokolwiek, którego używasz). Jeśli nie zrestartujesz ich jawnie i jeśli podczas ponownego uruchamiania OSx zaznaczono pole wyboru „Uruchom ponownie okna podczas ponownego logowania” (co jest ustawieniem domyślnym) - te programy nie będą odczytywać świeżych zmiennych środowiskowych.
Ran
21

Możliwe jest ustawienie zmiennych środowiskowych w systemie Mac OS X 10.10 Yosemite za pomocą 3 plików + 2 poleceń.

Plik główny z definicją zmiennych środowiskowych:

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

Definicja usługi do ładowania zmiennych środowiskowych dla aplikacji użytkownika (terminal, 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>

Ta sama definicja usługi dla aplikacji użytkownika 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>

I na koniec powinniśmy zarejestrować te usługi:

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

Co otrzymujemy:

  1. Jedyne miejsce do deklarowania zmiennych środowiskowych systemu: / etc / environment
  2. Natychmiastowa automatyczna aktualizacja zmiennych środowiskowych po modyfikacji pliku / etc / environment - wystarczy ponownie uruchomić aplikację

Problemy / problemy:

Aby zmienne env zostały poprawnie pobrane przez aplikacje po ponownym uruchomieniu systemu , będziesz potrzebować:

  • albo zaloguj się dwukrotnie: login => wyloguj => zaloguj się
  • lub ręcznie zamknij i ponownie otwórz aplikacje, w których należy wziąć zmienne env
  • lub NIE używaj funkcji „Otwórz ponownie okna podczas ponownego logowania”.

Dzieje się tak, ponieważ Apple zaprzecza wyraźnemu porządkowaniu załadowanych usług, dlatego zmienne env są rejestrowane równolegle z przetwarzaniem „kolejki ponownego otwarcia”.

Ale w rzeczywistości restartuję system tylko kilka razy w roku (w przypadku dużych aktualizacji), więc nie jest to wielka sprawa.

ursa
źródło
Świetny pomysł. Próbowałem i działa dla większości zmiennych środowiskowych (takich jak JAVA_HOME), ale nie dla PATHzmiennej (patrz moje pytanie na pytanie inaczej ).
halloleo
4
PATH należy ustawić za pomocą pliku / etc / paths. Wystarczy dodać niestandardową ścieżkę na końcu tego pliku.
ursa
Nie znam się tak dobrze launchd, ale czy nie byłoby możliwe załadowanie tych demonów przy rozruchu (tj. Przed zalogowaniem)? To powinno obejść wszystkie wymienione przez Ciebie problemy.
Egon
Uwielbiam powyższe podejście, ale mam dziwny problem do rozwiązania. Po ponownym uruchomieniu gen VARNAME zwraca mi poprawną wartość, ale echo $ VARNAME nic nie zwraca. Co może być tego przyczyną?
Wysłałem
Upewnij się, że uprawnienia do plików w / etc / environment są takie, jak opisano powyżej.
imanuelcostigan
6

Cytowano z

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

Po wielu rozważaniach inżynierowie usunęli tę funkcję. Plik /etc/launchd.confzostał celowo usunięty ze względów bezpieczeństwa. Aby obejść ten problem, możesz uruchamiać się launchctl limitjako root na początku rozruchu, być może z LaunchDaemon. (...)

Rozwiązanie:

Wpisz kod w /Library/LaunchDaemons/com.apple.launchd.limit.plistbash-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
aax
źródło
1
Czy możesz to trochę wyjaśnić? Nie rozumiem, w jaki sposób „Rozwiąż problem” odnosi się do pierwotnego problemu!
Nick H247
Nie OP, ale myślę, że istotą tego jest: włóż ten plist do /Library/LaunchDaemonsi zamiast mówić launchctlpolecenie uruchomienia limitpolecenia, powiedz mu, aby uruchomiło setenvpolecenie PATHi ciąg ścieżki jako argumenty. launchdpowinien podnieść go automatycznie przy starcie i niemal natychmiast dokonać automatycznej modyfikacji.
Laird Nelson
5
Plik XML nie został całkowicie skopiowany. Wiersz <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
doctype
6
@ax, która część tego plist faktycznie ustawia zmienną środowiskową?
HairOfTheDog
3

Oto polecenia przywracające stare zachowanie:

# 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

Teraz możesz określić polecenia takie jak setenv JAVA_HOME /Library/Java/Homew /etc/launchd.conf.

Sprawdzone na El Capitan.

Janchenko
źródło
2

Co zadziałało dla mnie (zainspirowane podziękowaniami aax):

Wklej to do /Library/LaunchDaemons/com.apple.launchd.limit.plist, a następnie uruchom ponownie:

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

Jeśli potrzebujesz tego krok po kroku:

  • Uruchom terminal
  • Wpisz sudo su, a następnie wprowadź hasło, aby zalogować się jako root
  • Wpisz vi /Library/LaunchDaemons/com.apple.launchd.limit.plist
  • W edytorze vi naciśnij klawisz i, aby przejść do trybu wstawiania, a następnie wklej dokładną treść kodu powyżej ( ⌘+v). Wymusi to ograniczenie do 16384 plików na proces i 16384 plików ogółem
  • Zapisz plik i zamknąć za pomocą escnastępnie:wq
  • Uruchom ponownie system i sprawdź, czy działa, używając komendy launchctl limit

Mam nadzieję, że to ci pomogło.

Baptiste
źródło
10
Co to rozwiązanie ma wspólnego z ustawianiem zmiennych środowiskowych?
HairOfTheDog
2

Możesz spróbować https://github.com/ersiner/osx-env-sync . Obsługuje aplikacje wiersza polecenia i GUI z jednego źródła i działa z najnowszą wersją systemu OS X (Yosemite).

Możesz używać podstawiania ścieżek i innych sztuczek powłoki, ponieważ to, co piszesz, to zwykły skrypt bash, który w pierwszej kolejności jest pozyskiwany przez bash. Bez ograniczeń .. (Sprawdź dokumentację osx-env-sync, a zrozumiesz, jak to osiągnąć).

Odpowiedziałem na podobne pytanie tutaj, gdzie znajdziesz więcej.

Ersin Er
źródło
-3

Rozwiązaniem jest dodanie zmiennej /etc/profile. Wtedy wszystko działa zgodnie z oczekiwaniami! Oczywiście MUSISZ to zrobić jako użytkownik root z sudo nano / etc / profile. Jeśli edytujesz go w jakikolwiek inny sposób, system będzie narzekał na uszkodzony profil / etc /, nawet jeśli zmienisz uprawnienia do rootowania.

Ilias
źródło
7
Dodawanie zmiennych środowiskowych do profilu jest znacznie gorsze, ponieważ wpływa tylko na procesy powłoki.
UloPe,
-5

Dodałem zmienne do ~ / .bash_profile w następujący sposób. Po zakończeniu uruchom ponownie / wyloguj się i zaloguj

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

UWAGA: bez ponownego uruchomienia / wylogowania i zalogowania można zastosować te zmiany za pomocą;

source ~/.bash_profile
Rudzik
źródło
Pamiętaj, że nie musisz się wylogowywać i ponownie logować. Wystarczy użyć polecenia source, tj. Source .bash_profile.
Michael
2
Problem z tą metodą polega na tym, że nadal musisz otworzyć terminal, zanim zmienne środowiskowe będą dostępne. Lepiej zrobić to, co jest w pierwszej odpowiedzi, aby były dostępne bez konieczności otwierania terminala.
Michael,
1
To nie działa na aplikacjach ładowanych przez SpotLight. stackoverflow.com/questions/135688/…
Rasika Perera
1
Korzystanie z plików konfiguracyjnych bash ma ograniczoną pomoc, ponieważ zakłada, że ​​zawsze masz basha jako przodka procesu, którego środowisko chcesz osiągnąć. Spotlight, wyszukiwarka, emacs, xcode, cronjobs, uruchomione agenty, dowolne IDE, przeglądarki kontroli źródeł itp. Itd. - nie będą bash jako przodkowie. Jedynym procesem, który może obejmować te konsekwentnie, jest uruchomienie.
Ben Hyde