LoginSignup
52
50

More than 5 years have passed since last update.

dirname、basenameは「%/*」と「##*/」で書くと処理速度が早くなる

Last updated at Posted at 2015-10-14

さっきの記事を書いているときに面白いものを見つけた。

bash では basename や dirname を使うより ${0##/} や ${0%/} を使ったほうが速い?

dirnameで行えることを変数内(${})で行ってしまおうというもの。
しかもこれで行うと処理速度が早いらしいので実際やってみた。

実際に実行してみる

hoge.sh
#!/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 の機能。つまり、##*/ と書けば先頭から最後のスラッシュまでを取り除く。

早さもチェック。

負荷テスト

stress_test.sh
#!/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では最後に「/」があっても認識してくれるのに、「##*/」だとしてくれない。
こういう方法もあるよという知識として。

52
50
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
52
50