2012-09-13 8 views
10

Zainstalowałem rbenv przez homebrew, a teraz nie wiem dlaczego path_helper umieściło ~/.rbenv/shims na końcu ścieżki zamiast na początku. A co najważniejsze, w jaki sposób path_helper otrzymał te informacje?OS X Mountain Lion: jak działa path_helper?

Zgodnie ze stroną podręcznika path_helper odczytuje wpisy z/etc/paths iz plików w /etc/paths.d. Ale nie mogę znaleźć tam łańcucha ".rbenv/shims".

~% cat /etc/paths 
/usr/bin 
/bin 
/usr/sbin 
/sbin 
/usr/local/bin 
~% ls -la /etc/paths.d 
total 0 
drwxr-xr-x 2 root wheel 68 Jun 21 03:16 . 
drwxr-xr-x 107 root wheel 3638 Sep 10 09:59 .. 
~% /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Users/gordon/.rbenv/shims"; export PATH; 

Odpowiedz

6

Podejrzewam, że twój .bash_profile lub .bashrc jest dodanie .rbenv/shims do ścieżki, i że działa w pewnym momencie przed path_helper jest wywoływana podczas rozruchu powłoki.

Strona man dla path_helper otwiera:

The path_helper utility reads the contents of the files in the directo- 
ries /etc/paths.d and /etc/manpaths.d and appends their contents to the 
PATH and MANPATH environment variables respectively. 

Zasadniczą kwestią jest to, że narzędzie path_helper ma dodać zawartość do istniejącego ustawienia PATH, nie je zastąpić. (A w rzeczywistości, co to naprawdę jest prepend zawartość, a nie je dołączyć, który liczy na PATH zmiennych ...)

Tak więc, jeśli zacznę się z wpisem na moim PATH ustawienie generowane przez path_helper zapewni, że wejście będzie kontynuowane na wygenerowanym PATH.

% echo $SHELL 
/bin/bash 
% uname 
Darwin 
% /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin"; export PATH; 
% PATH="" /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin"; export PATH; 
% PATH=foo /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo"; export PATH; 

Zauważ, że foo została ujęta w moim ścieżka w ostatnim wierszu, choć zawartość /etc/paths i /etc/paths.d/* nie uległy zmianie.

Jednocześnie narzędzie path_helper wydaje się być ostrożne, aby nie tworzyć ścieżek z duplikatami; usuwa zduplikowane wpisy po konkatenacji /etc/paths i /etc/paths.d/* i bieżącym PATH.

Ten ostatni szczegół może być szczególnie mylący, ponieważ może spowodować zmianę kolejności wpisów w porównaniu do oryginalnego ustawienia (!).

Poniżej znajduje się kilka przykładów tego zachowania: Pierwszy przypadek pokazuje usunięcie duplikatu foo. Drugi i trzeci przypadek ilustrują zmianę kolejności wpisów: wygenerowana PATH jest taka sama w obu przypadkach, ale w trzecim przypadku wpis /usr/bin został przeniesiony z pomiędzy foo i bar z przodu PATH. (Wydanie tego duplikatu wydaje się być oparte tylko na prostym dopasowywaniu ciągów na parach wpisów, co ilustruje czwarty przypadek poniżej, gdzie ciąg /usr/bin/ pozostaje między foo/ i bar.)

% PATH=foo:foo /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo"; export PATH; 
% PATH=foo:bar /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo:bar"; export PATH; 
% PATH=foo:/usr/bin:bar /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo:bar"; export PATH; 
% PATH=foo/:/usr/bin/:bar /usr/libexec/path_helper 
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:foo/:/usr/bin/:bar"; export PATH; 

Wreszcie, aby dać kredytu w przypadku gdy kredyt jest spowodowane: Podczas gdy wszystkie sekwencje poleceń powyżej są rezultatem moich własnych badań, byłem początkowo inspirowany zajrzeć do zachowania path_helper po przeczytaniu notatki here , , która wskazała, że ​​path_helper ponownie używa zmiennej środowiskowej PATH ustawionej przez proces macierzysty.

+1

Dzięki za wskazanie, że, contra the docs, path_helper * dodaje * ścieżki i usuwa duplikaty. – algal

6

Strona podręcznika systemowego path_helper jest niepoprawna. Strona man mówi, że path_helper dołącza /etc/paths.d do PATH. W rzeczywistości path_helper jest ZAŁĄCZNIKIEM /etc/paths.d na listę z/etc/paths, a następnie skutecznie OZDOBAJ ten wynik do rzeczywistej istniejącej wcześniej PATH (a także do usunięcia PATH z nadpisanych duplikatów z tej listy).

Aby być dokładnym, mówiąc tylko PATH Na przykład, co robi jest:

  1. przeczytać listę ścieżek w pliku/etc/ścieżek
  2. DOŁĄCZ na nią list ścieżek w pliki w katalogu /etc/paths.d
  3. mutować zmienną PATH, aby usunąć wszelkie przedmioty z listy
  4. dopisywania na listę wartości zmiennej PATH zmutowanego
  5. Zapisz tę listę jako nową ścieżkę

przeformułowanie to w Pseudokod, co robi jest:

  1. newpath = Odczyt (/ etc/ścieżki)
  2. newpath = $ newpath + dołączy + czytaj (/etc/paths.d/ *)
  3. PATH = $ PATH -minus- $ newpath
  4. newpath = $ newpath + dołączy + $ PATH
  5. PATH = $ newpath

To, co jest zdradzieckie, polega na tym, że jeśli ręcznie konfigurujesz swoją ścieżkę PATH, prawdopodobnie ma to na celu dodanie komponentów, które przesłaniają komponenty ścieżki systemowej. Jeśli wywołanie funkcji path_helper zostanie wywołane, gdy się tego nie spodziewasz, cofnie zmiany, umieszczając komponenty ścieżki systemowej przed komponentami ścieżki.

W jaki sposób pomocnik ścieżki zostanie wywołany nieoczekiwanie? Na przykład, jest wywoływana przez/etc/zshenv, która jest wywoływana za każdym razem, gdy uruchamiasz powłokę zsh, niezależnie od tego, czy jest to podpowłodzenie, czy instancja zsh z innej aplikacji, np. Emacs, czy cokolwiek innego.

Napisałem go bardziej szczegółowo jako OpenRadar bug report on path_helper.

+0

Oto próba ulepszenia, jeśli ktokolwiek ma ochotę go używać/sprawdzanie przez https://github.com/yb66/path_helper – iain

+0

W OS El Capitan 'path_helper' jest wywoływane w'/etc/zprofile' zamiast '/ etc/zshenv', który, jak argumentuję, jest * gorszy *. Co najmniej '/ etc/zshenv' było pierwszą rzeczą, z której pochodzi, więc można by nadpisać' PATH' dla wszystkich powłok (interaktywnych, nieinteraktywnych) w '~/.zshenv'. Ale ponieważ '/ etc/zprofile' jest pobierany po' ~/.zshenv', jeśli chcesz mieć tę samą 'PATH' dla interaktywnych i nieinteraktywnych powłok, musisz powtórzyć modyfikacje wykonane w' ~/.zshenv' w '~/.zprofile'. – rampion