hashってなに?
起動したコマンドが、何処にあったのか、2回目以降のPATH検索を省略する機能です。
PATH環境変数を変えた後、コマンド行方不明⇛hashによるキャッシュ
PATHをいじった後に、コマンドの場所変更が、反映されないことってあるよね
#bashの場所の確認 takuya$ which bash /usr/local/bin/bash # 消してやる takuya$ rm /usr/local/bin/bash #消しても /bin/bashにあることを確認 takuya$ which bash /bin/bash #PATH=/bin: あるから bashで起動するよね! takuya$ bash -bash: /usr/local/bin/bash: No such file or directory ## あれれ?おかしいなー
bashを削除しても、/bin/bashがあるはずなのに、なぜか起動しない。
こんな経験ありませんか。
No such file or directoryの原因はhashかもよ。
もう予想通りだと思いますが、bashのコマンドの検索順序はPATHの順序ではなく。。。
- hash テーブル
- $PATH
の順番になっています。
hashは、起動したコマンドをキャッシュしている
hashは、起動したコマンドのフルパス名を記憶してキャッシュしています。
なので、hashに残ってる物を起動しようとしてエラー
ハッシュテーブルを確認すると、まだ残っている。
takuya@rena:~/Desktop$ hash hits command 1 /usr/local/bin/bash
bashと叩いて、hashテーブルのbashを探して起動しようとするからエラーになる。
hashテーブルをリセット
hash -r
このコマンドで、hashテーブルを空にしてやると全て解決する、cshとかだとrehash相当
空っぽになったhashテーブル
takuya@rena:~/Desktop$ hash -r #初期化 takuya@rena:~/Desktop$ hash hash: ハッシュテーブルが空です
hashって速いの?
実は速度を測ってみたけど、あんまり変わらなさそう
takuya@rena:~/Desktop$ time hash-non.sh real 0m0.340s user 0m0.128s sys 0m0.145s takuya@rena:~/Desktop$ time ./hashed.sh real 0m0.330s user 0m0.126s sys 0m0.140s
圧倒的な違いはないっぽいけどね。
測定に使ったコード
hashの有利なところ
- 先にHashしておけば、PATHの順番を無視して、優先度変えられる
- PATHをドンドンドンドン増やした時に毎回毎回たどる手間が減る。
- コマンドの実行回数をカウントしてくれる
など。とくに同名コマンドのPATH優先度を工夫しなくていい点は便利だと思う。
hashの状態を確認する
takuya@rena:~/Desktop$ hash hits command 1 /usr/local/bin/bash 1 /bin/zsh 3 /usr/local/bin/ruby 1 /usr/bin/python
hashをリセットする
takuya@rena:~/Desktop$ hash -r takuya@rena:~/Desktop$ hash hash: ハッシュテーブルが空です
最初からhashしたい
hashした状態で起動しておけば楽じゃん?強引に優先度変えられるし。
そういうときは・・・ hash -l を叩くとhash追加コマンド出てくる
takuya@rena:~/Desktop$ hash ##確認 hits command 1 /usr/local/bin/bash 1 /usr/local/bin/ls 1 /usr/local/bin/ruby 1 /usr/local/bin/find 1 /usr/bin/python takuya@rena:~/Desktop$ hash -l ## bashrcにかける形式 builtin hash -p /usr/local/bin/bash bash builtin hash -p /usr/local/bin/ls ls builtin hash -p /usr/local/bin/ruby ruby builtin hash -p /usr/local/bin/find find builtin hash -p /usr/bin/python python
たとえば ruby をhashしておきたいときは
builtin hash -p /usr/local/bin/ruby ruby
とbashrc に書いておけばイイ。そうするとrbenvのrubyより優先されて便利になる。
たとえば、 ls を /bin/ls にするとか
builtin hash -p /bin/ls ls
上記を実行すれば、PATH=/usr/local/bin:/bin で、/usr/local/bin/lsがあったとしても、 ls で /bin/ls が起動する。
2016/12/27 追記 csh などrehash を使ってる人向け
bashにrehashはないです。rehash が bashにはないので alias して使うといいです。
alias rehash='hash -r'
2016-12-27 追記
hash は、コマンドで確認できるだけじゃく、変数でも確認することが出来ます。
BASH_CMDS
にhash されたコマンドが入っています。
echo ${BASH_CMDS[@]}
でハッシュされたコマンドの一覧を見ることが出来ます。