それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

bash(csh)のhashとか言う、気づかないけど便利な機能

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の順序ではなく。。。

  1. hash テーブル
  2. $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

圧倒的な違いはないっぽいけどね。

測定に使ったコード

gist605b6c29b2fd42566c97

gistf62a702701672ce63475

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[@]}

でハッシュされたコマンドの一覧を見ることが出来ます。

参考資料

hashコマンドって何? - Qiita