ラベル PATH の投稿を表示しています。 すべての投稿を表示
ラベル PATH の投稿を表示しています。 すべての投稿を表示

2013年1月31日木曜日

PATH環境変数の設定はどうなっている

PATH変数に定義するディレクトリの並びについて書きましたので、ターミナルにログインした時に、PATH変数がどのように設定されるのかについて書きたいと思います。一応、bashを使っている場合です。

大体、以下の流れになります。

  1. ターミナル.appが立ち上がる際にされる設定
  2. /etc/profileで行われる設定
  3. /etc/bashrcで行われる設定
  4. ユーザの~/.bash_profileで行われる設定
  5. ユーザの~/.bashrcで行われる設定

ターミナル.appが立ち上がる際にされる設定

ターミナル.appをDockなどから立ち上げる際に、launchd関係でPATH設定をしているとPATH環境変数が設定されます。他にもあるかもしれません。個人的には、bash本来の/etc/profile以降だけで設定される方が好きです。

/etc/launchd.conf - launchd経由で立ち上がるプロセスに適用されます。setenv PATH path_name1:path_name2:... のようにcsh系と似た記述で指定します。
launchd.plist - 使っていないのでわかりませんが、manをみるとEnvironmentVariables <dictionary of strings> で、XMLフォーマットでPATHを指定できそうです。対象は、launchd本体、Terminal.appなどでしょうか。

また、ターミナル.app自体の環境設定で特別なコマンドを指定しているとそこでPATHが指定される可能性もありますね。この場合は、あえて指定しているので問題ないと思いますが。

その後、ターミナルが立ち上がると、ウインドウが開きシェルが起動されます。デフォルトでは/usr/bin/login経由で、/bin/bashが立ち上がります(変更等していない場合)。以下にbashの場合を説明します。

/etc/profileで行われる設定

bashは、起動すると/etc/profileを実行します。デフォルトでは、その中でpath_helperが実行され、/etc/pathsに記述してあるディレクトリをPATHに設定します。その後、/etc/paths.dに記述してあるファイルをアルファベット順に読んで、中に記述してあるディレクトリをPATHに追加していきます。PATHの前の部分に挿入することはできないようです。paths.d内のファイル名が"-" (マイナス)等で始まる場合は、前の部分に付加できるなどの仕様になっているといいと思ったのですが。

/etc/profileの中から/etc/bashrcが実行されます。

/etc/bashrcで行われる設定

デフォルトでは/etc/bashrcでは、特にPATHの設定は行われていないようです。
次から、ユーザの~/.bash_profileが実行されます。

~/.bash_profileで行われる設定

.bash_profile以降は、ユーザがどのように書いたかに大きく依存しますので、あまり解説しても意味が無いかもしれません。ここでは私の場合を説明します。
私の.bash_profileでは、それ自身では細かい設定は行わず、.bashrc, .profileをそれぞれ呼び出しているだけです。

~/.bashrcで行われる設定

私は、ここでPATH変数の頭に~/bin, ~/local/bin、/usr/local系、/opt/local系を付加しています。また、PATHの最後にclamXavを追加しています。

~/.profileで行われる設定

私は、.profileは使っていませんでした。

この記事を書いていて、.bashrcにあまりよくない記述も見つかったので直したくなってきました。よさそうな修正ができたらこのブログにも書きたいと思います。

2013年1月29日火曜日

PATH環境変数内の、~/bin, /bin, /usr/bin, /usr/local/binなどの順番

ターミナルでシェルを使う場合の小ネタです。初心者には重要かもしれません。知っている人は今さらと思うかもしれませんが。
私は、以前はtcshを使っていました。Mac OS X 10.6.2までターミナルのデフォルトのシェルだったからです。Tiger (10.6.4)の時からbashにしました。乗り換えが1世代遅れたのは、使い方に若干慣れないところがあったのと、.tcshrcから.bashrc, .bash_profileへの変更が面倒だったためです。シェルスクリプトは/bin/shで書くことにしています。

今回の本題は、tcsh, bashのどちらにも関係するのですが、PATH環境変数内に設定するディレクトリの順番です。別の考え方もあると思いますので、参考ということで。

PATH環境変数は、コマンドを探すときのディレクトリの順番を指定するものです。PATH変数に含まれていないディレクトリにあるコマンドを指定しても、"コマンドが見つかりません"といったエラーがでます。

$ chdir
-bash: chdir コマンドが見つかりません

ディレクトリにコマンドが存在するのに上のようなエラーが出る時は、PATH環境変数にそのディレクトリが含まれていない(PATHが通っていないと言いますね)か、そのコマンドに実行権がないか、csh系だとrehashしていないという場合が多いです。(自分の経験では)

現在の私のPATH環境変数は、以下のようになっています。

$ echo $PATH
/Users/karuku/bin:/Users/karuku/local/bin:/usr/local/bin:/opt/local/bin:/usr/local/sbin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/clamXav/bin

基本的な考え方は、特殊なもの、局所的なものを先頭に持ってくる、標準的なものは後ろにするというふうにしています。一部、その考え方に沿っていないところもありますが。

定義順にそれぞれの使用目的を書いてみます。

/Users/karuku/bin - ホームディレクトリ下のbinです。自分で作成したスクリプト類を置いています
/Users/karuku/local/bin - テスト目的でインストールしたいものを置いています
/usr/local/bin - MacPortsでサポートされていないコマンドを置いています
/opt/local/bin - MacPortsでサポートされているコマンドを置いています
/usr/local/sbin - MacPortsでサポートされていないシステムコマンドを置いています
/opt/local/sbin - MacPortsでサポートされているシステムコマンドを置いています
/usr/bin - 一般的なユーティリティ、プログラミングツール、アプリケーション
/bin - ユーザ用ユーティリティの基本的なもの。シングルユーザ環境、マルチユーザ環境どちらでも使用する
/usr/sbin - (ユーザによって実行される) システムデーモン、およびシステムユーティリティ
/sbin - (ユーザによって実行される) システムデーモン、およびシステムユーティリティ
/opt/X11/bin - XquartzでインストールされるX Window System
/usr/local/clamXav/bin - ウィルスチェッカー clamav / clamXavをインストールしています。

( /binや/usr/binなどのシステムディレクトリ説明にはjman hierの記述を使いました。)

最後のふたつの /opt/X11/binと/usr/local/clamXav/binは、最初の考え方の原則に反していますね。

/opt/X11/bin (X11)は、Xquartsをインストールした際に、/etc/paths.dに登録されました。ここに登録されると、ログイン時に/etc/profile内で、その時のPATH変数にアペンドされる形になるようです。
X11は、以前Mac OS Xに使いたいGUIアプリケーションが少なかったころや、会社でLinuxマシンを使う際に使っていましたが、最近は全く使っていません。LinuxかFreeBSDを使うこともなさそうなので、当面このままにするつもりです。

clamXavは、ターミナルからではなく、Finderから使う場合がほとんどなので、PATHから外してもいいかもしれないですね。

コマンド名がぶつかる場合

たまに、同名のコマンドがそれぞれのディレクトリにある場合があります。上の考え方の場合、通常は使いたいコマンドが先に来ているので問題ないのですが、たまに後のディレクトリのコマンドをデフォルトとして使いたい場合があります。
例えば、rsyncはAppleの提供しているバージョンとMacPortsでインストールされるバージョンでは、HFS+関係の属性等を扱うオプションが違います。MacPortsのrsyncを使おうと思った訳ではなく、依存関係でインストールされたのですが。

こういう場合は以下のようにしています。

シェルスクリプトの場合は、以下のようにフルパスで記述します。

RSYNC=/usr/bin/rsync
RSYNC -hfsv ...

コマンドラインから使う場合は、~/bin から使いたいバージョンのコマンドにシンボリックリンクを張ります。~/binは先頭にあるので、意識せずに使いたいバージョンのコマンドが使えます。

$ ln -s /usr/bin/rsync ~/bin

別の解決方法として、alias が考えられますがあまり使っていません。特に意識していませんでしたが、bashの場合、whichコマンドでaliasで定義したコマンドが表示されないから(方法を知らないだけかもしれませんが)というような理由です。
また、bashに移行した初めの頃は、tcshも併用していたので、~/binの一箇所に設定しておけばいいからという理由もあったかもしれません。(ちょっとうろ覚えです)