闇のpath_helperに対する防衛術 (※2025年時点)
About this scraps
macOSの path_helper
について掘り下げて悩んでまとめる
path_helper問題の歴史 (2025年時点)
- 1999年:
- 2008年:
- 2009年:
- OS X Snow Leopard リリース。
-
path_helper
が現在のバイナリ形式に変更された。なんと2021年までソースコードが公開されていた模様。現在でも2012年ごろのソースは閲覧できる[5]。
- 2012年?:
- 2013年:
- 「
path_helper
は壊れている!」「/etc/zshenv
を/etc/zprofile
にすれば解決する!」という論争が起こる[8]。
- 「
- 2015年9月末
- 2015年末~2016年?:
- 2017年:
- macOS用の.NET Core がインストール時に
/etc/paths.d/dotnet
を生成する事例が投稿される[12]。
- macOS用の.NET Core がインストール時に
- 2018年:
- 2021年:
- VMware Fusionが
/etc/paths.d/com.vmware.fusion.public
を残していく事例が投稿される[15]。
- VMware Fusionが
- 2023年:
- 私が手元でインストールしたgoが
/etc/paths.d/go
を生成していた。
- 私が手元でインストールしたgoが
-
New features in zsh version 3.1.6 (beta version) - Release Notes ↩︎
-
The notice about
path_helper
on OS X is incorrect · Issue #381 · sorin-ionescu/prezto ↩︎ -
path_helper ($PATHを設定するコマンド) (macOS, /etc/paths.d, /etc/paths, shell間をまたいだパス設定) - いろいろ備忘録日記 ↩︎
-
zsh: default unicode9, remove options. by MikeMcQuaid · Pull Request #34422 · Homebrew/homebrew-core ↩︎
-
VMware Fusionのアンインストール後も/etc/paths.d/com.vmware.fusion.publicが残る - あとがきのようなもの ↩︎
主張・思想
人々が何を主張しているのかわからなくなってきた
派閥
-
~/.zshenv
より後でPATH
をいじって欲しくないよ派:- これはほんとうにそう
-
PATH
以外はいじられないので、〇〇env
としての体裁は保てている?
-
そもそも
path_helper
は 壊れている・バグがある よ派:- 正直わからない
-
/etc/zshenv
に置かれていたのは問題あると思うケド(全シェルで毎回PATH再設定してるのはさすがにちょっと変)…… - 2025年現在も壊れてるって主張は、ちょっとキレすぎじゃないかナ
-
path_helper
がPATH
の順番をいじらなければ問題はなかったはずだよ派:- これもほんとうにそう
- 事前に
PATH
の値を取得しておいて、それを尊重するような動作にして欲しかった - (もしかしてmacOS的には
zshenv
を使って欲しくないのか?)
-
/etc/paths
,/etc/paths.d/*
をいじっちゃえばいいよ派:- わからない
- 全ユーザに影響が及ぶし、起動スクリプトの中にこれに依存するものがないとは言い切れない
-
no_global_rcs
,--without-etcdir
で丸ごとスキップしちゃえばいいよ派:- わからない
- 2023年時点でも
/etc/paths.d
は使われているので、path_helper
を排除するのは厳しい - ただ、昔はこれが唯一無二の解決策だった可能性はある
-
諦めて
~/.zshrc
で設定するのが一番楽だよ派:- 正直わかる
- ただそれは
〇〇rc
の責任じゃないと思う
要約
- macOSには
path_helper
というPATH設定ヘルパが存在する -
~/.zshenv
より後に呼ばれるので、他環境のdotfileを持ってくるとPATHがおかしな順番になることがある - この子は問題なく動作するが、デフォルトのコマンドを置き換えたいときにとても困る
- 一部のプログラムは
path_helper
が動作することを前提にしているので、我々はこの子と共存しなければならない
path_helper
とうまくやっていくには?
上述の通り path_helper
は2025年現在も使われているため、削除・スキップ等の手段で解決するのはよろしくない
ではどうすればよいのか
Apple (macOS) の意図を推測する
path_helper
実装初期)
OS X Leopard ~ (この時点では path_helper
は /etc/zshenv
で呼ばれていたことから、いかなる状況でもシェルコマンド実行前に path_helper
が実行されること を想定していた可能性が高い。
どのようにシェルが起動されようと滞りなくコマンドサーチパスが設定されるよう、 (中略) zsh用の「/etc/zshenv」に、path_helperを実行するための記述が施されている。
2010/10/12, ZDNet Japan [1]
この時代のメジャーな解決策は /etc/paths.d/
にファイルを追加する……というものだったよう:
It is very handy. All you do is create a file in /etc/paths.d that contains a single line, the directory you want to add to your path.
2010/02/20, Apple community [2]
If you need to run your PHP commands as CLI sessions, you'll also probably need to add /opt/local/bin as a new path under /etc/paths.d work. For instance, something like this:
shell> sudo echo "/opt/local/bin" >> /etc/paths.d/macports
2008/09/23, Apple Mailing Lists [3]
Messing with the [/etc/|~/.] of [profile|bashrc] files may work, but it's somewhat of a hack. The /etc/paths.d/ directory is the way to go:
2008/12/07, serverfault [4]
echo "/some/other/path" >> /etc/paths.d/GoogleDev
same for /etc/manpaths.d
Just create files with the path/manpath additions you want in those locations.This is one of the most awesome things Apple has done
2009/09/28, Ars OpenForum [5]
しかし、この頃から手放しで称賛されていたわけではなかった:
I've always been quite happy about most of the stuff Apple does. A lot of their solutions to problems are elegant and pretty. However, there are also some cases in which they do awful stuff under the hood. Stuff that makes me cringe in disgust.
Case in point, the new path_helper command.
2007/11/18, www.kilala.nl [6]
Snow Leopard 以前では、path_helper
が呼ばれる前の段階で PATH
が設定されてしまっており、本来設定されるべきでない値が返るバグが存在した:
However, if you want to change the order of path lists in /etc/paths, changing the order of lines in this file seems useless ! This because the PATH variable has an initial value of /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin before a call to path_helper take place. While the origin of this initial value stay obscure to me, this is a true fact.
2008/06/24, SOFTEC.st [7]
つまり人類はもう15年以上このプログラムと格闘しているということになる
/etc/zprofile
への移動)
OS X El Capitan ~ (zshのメーリングリストでパスの変更が報告されている。
That's good news, they used to have that code in /etc/zshenv which meant you had no way to override it. It only took them a few years to fix this.
2015/07/31, Zsh Mailing List Archive [8]
しかし、Appleが path_helper
を /etc/zshenv
から /etc/zprofile
に移動した明確な動機は見つからなかった。この変更の詳細は不明だが、異なるシェル感の挙動を統一したかった意図もあったのではと個人的に考えている。
それまで、 path_helper
の呼び出しは /etc/zshenv
に加え /etc/profile
にも書かれていた。このファイルは bash
がログインシェルとして起動した際にのみ読み込まれるが、zsh (5.9 (arm-apple-darwin24.0.0)) では読み込まれない。
つまりzshは /etc/zshenv
から、 bashは /etc/profile
から path_helper
を呼ぶことになる。
/etc/zshenv
は常に読み込まれるため、以下のような挙動のねじれが発生する:
インタラクティブシェル | 非インタラクティブシェル | |
---|---|---|
ログインシェル | bash/zsh | bash/zsh |
非ログインシェル | zsh | zsh |
このねじれを「ログインシェルとして起動した際 path_helper
が一度だけ呼ばれる」という挙動に統一したかった可能性はある。シェルが起動するたびに path_helper
が呼ばれてしまうと サブシェルを起動するだけでPATHの順序が変わる ことになり(多分)、挙動としてもなにやらおかしなことになってしまう。
-
How do I set the $PATH environment variab… - Apple Community ↩︎
-
Re: How to create/change an environment variable (path) for user "_www" in Mac OS-X Leopard ↩︎
-
mac osx - How do I set the global PATH environment variable on OS X? - Server Fault ↩︎
-
how do i add something to PATH in snow leopard? | Ars OpenForum ↩︎
-
kilala.nl - path_helper: sometimes Apple does kludgy, stupid things ↩︎
-
Re: PSA: Mac OS X El Capitan upgrade might break your $PATH ↩︎
path_helper
とは
プログラムの概要
macOSの /usr/libexec/path_helper
にデフォルトで存在するコマンド。man曰く、
helper for constructing
PATH
environment variableThe path_helper utility reads the contents of the files in the directories
/etc/paths.d
and/etc/manpaths.d
and appends their contents to thePATH
andMANPATH
environment variables respectively.
つまり特定のディレクトリ以下にあるファイル群からPATH
を構成・出力するもの。
シェル起動時に -l
を与えるとログインシェルとして起動する。
現在のシェルプロセスがログインシェルかどうかは以下のスクリプトで確認できる[1]:
if [[ -o login ]]; then echo "login"; else echo "not login"; fi # 'login' or 'not login'
ターミナル.appでは、「デフォルトのログインシェル」が選択されている場合は毎回 -il
が渡される = ログインシェルかつインタラクティブシェルとして起動する
% ps aux | grep /bin/zsh
user 26312 0.0 0.0 410808784 4560 s008 Ss+ 3:38PM 0:00.34 /bin/zsh -il
VSCodeはデフォルトで -l
が渡される (terminal.integrated.profiles.<platform>
で設定できる[2])
明示的にオプションが渡されなければログインシェルにはならない。
- パスを指定して実行した場合 (
./script.sh
,/path/to/script.sh
)、スクリプトが実行されるのは非ログインシェルとなる。shebangで-l
を設定すると、再度ログイン処理(?)が走る。 - built-in command[1] の
.
で実行した場合(. ./script.sh
)は、現在の環境を引き継ぐため、スクリプトが実行されるのはログインシェルとなる。 -
zsh
に直接渡した場合は (当然ながら) コマンドラインオプションに依存する。
path_helper
問題とは
なぜ人々はこのコマンドに苦しめられているのか
歴史
OS X Leopard で追加されて以来、 path_helper
はさまざまな問題を引き起こしてきた。
ここではその歴史を振り返る。
path_helper
誕生
2007/10/26: OS X 10.5 Leopard リリース, Appleより、最初期バージョンの path_helper
を搭載した OS X Leopard がリリースされた。
当時はシェルスクリプトとして実装されていたこと、また現在とは異なり /etc/zshenv
から呼ばれていたことが判明している。「/etc/paths
および /etc/paths.d
を読んでPATHを生成する」一連の動作については、当初から疑問視する声が上がっていた。
また、この時点では path_helper
実行前の PATH
を引き継いでしまうバグ が存在したよう(Snow Leopardで修正された)。
Leopard introduced this great(?) new way of setting up default PATH and and MANPATH, in /usr/libexec/path_helper.
Leopard では、/usr/libexec/path_helper を用いてデフォルトの PATH と MANPATH を設定するための素晴らしい(?)新しい方法が導入された。
2008/11, PATH and other evironment issues in Leopard [1]
どのようにシェルが起動されようと滞りなくコマンドサーチパスが設定されるよう、 (中略) zsh用の「/etc/zshenv」に、path_helperを実行するための記述が施されている。(中略) なお、このpath_helperコマンドはLeopard当時シェルスクリプトだった
2010/10/12, Snow Leopard時代のパス管理術 - builder by ZDNet Japan [2]
I guess Apple's reasoning is that it's easier to add extra text files to /etc/paths.d, than it is to add a new PATH= line to /etc/profile. Personally, I think it an in-elegant (and rather wasteful) way of doing things :/
Wait, it's even worse! The path_helper gets called from /etc/profile! Ugh! :(Apple は、/etc/profile に新しく PATH=... を追加するよりも、/etc/paths.d にファイルを追加する方が簡単だと考えているのではないか。個人的には、これはあまりエレガントではない (むしろ無駄の多い) やり方だと思う :/
待て、これはさらに良くない!path_helper は /etc/profile から呼び出されている! :(2007/11/18, kilala.nl - path_helper: sometimes Apple does kludgy, stupid things [3]
どうやらpath_helperの実行前に元から設定されていたPATHが一番最初に来るようです。
2008/12/01, 最近のMac OSXで、PATHをスマート(?)に管理するやり方。 - こせきの技術日記 [4]
Therefore, if you want to place /use/local/bin in front of your path, you have to clean it before calling path_helper.
したがって、/usr/local/bin をPATHの先頭に置きたい場合、path_helperを呼び出すより前にPATHを初期化する必要がある。
2008/06/24, Mastering the path_helper utility of MacOSX
2009/08/28: OS X 10.6 Snow Leopard リリース
path_helper
の実装がシェルスクリプトからバイナリに変更された。また、当時は opensource.apple.com にてソースコードが公開されていた(2021年に削除, 現在でもアーカイブ[1]は閲覧可能)。