さっきの記事を書いているときに面白いものを見つけた。
bash では basename や dirname を使うより ${0##/} や ${0%/} を使ったほうが速い?
dirnameで行えることを変数内(${})で行ってしまおうというもの。
しかもこれで行うと処理速度が早いらしいので実際やってみた。
実際に実行してみる
#!/bin/bash
DIR="/home/hoge/bin"
echo 0.DIR:${DIR}
echo
echo 1.dir:$(dirname ${DIR})
echo 2.base:$(basename ${DIR})
echo
echo 3.dir:${DIR%/*} # 変数に対してdirnameを行う
echo 4.base:${DIR##*/} # 変数に対してbasenameを行う
$ ./hoge.sh
0.DIR:/home/hoge/bin
1.dir:/home/hoge
2.base:bin
3.dir:/home/hoge
4.base:bin
すごい。本当になっている。
${DIR%/*}
と${DIR##*/}
の部分は何を行っているのかは引用で説明させてもらう。
${DIR%/*}
変数内文字列置換の方は % で後方から最短一致で最初のスラッシュまでを削除する。
${DIR##*/}
${} 内の ## というのは この記事 でもちょっと書いたけど、変数内の文字列を先頭から最長一致で取り除く bash の機能。つまり、##*/ と書けば先頭から最後のスラッシュまでを取り除く。
早さもチェック。
負荷テスト
#!/bin/bash
DIR="/home/hoge/bin"
printf dirname、basename
time for ((i=0;i<=1000;i++))
do
echo $(dirname ${DIR}) >/dev/null
echo $(basename ${DIR}) >/dev/null
done
echo
printf %%/*、##*/
time for ((i=0;i<=1000;i++))
do
echo ${DIR%/*} >/dev/null # dirname
echo ${DIR##*/} >/dev/null # basename
done
$ ./stress_test.sh
dirname、basename
real 0m2.416s
user 0m0.505s
sys 0m1.866s
%/*、##*/
real 0m0.036s
user 0m0.024s
sys 0m0.012s
あまりにも早すぎて驚いた。
シェルの中にdirnameとbasenameを多用している人は置き換えた方がいいかも。
問題点
使っている時に気づいた問題点を上げる。
-
パスの最後に「/」がある場合、basenameが表示できない。
-
可読性が悪い。コメントを付けないと何をしているかわからない。
とりあえずこのくらいかな?
特にbasenameでは最後に「/」があっても認識してくれるのに、「##*/」だとしてくれない。
こういう方法もあるよという知識として。