(Un*x)dirname の繰り返し適用

今更ながらこれが鬱陶しいことに気付く。

本物の Unix ツールを本物の Unix で使う場合はこういうことはあんまり起こらないんだけれど、Windows なんかで「Unix 生まれのツールを、実行形式のみにパスを通して使う」ようないい加減なことを良くやるわけね。アタシの場合は ffmpeg なんぞがまさしくそうで、普段は「動かせりゃいい」ノリで /bin までを環境変数 PATH に追加するだけで満足している。

そうするとな、/bin だけでなく /include なんぞも楽に参照したい場合に毎度面倒くさい:

1 me@host: ~$ type -p ffmpeg
2 /c/Program Files/ffmpeg-20140916-git-b76d613-win64-static/bin/ffmpeg
3 me@host: ~$ dirname "`type -p ffmpeg`"
4 /c/Program Files/ffmpeg-20140916-git-b76d613-win64-static/bin
5 me@host: ~$ dirname "`dirname \"\`type -p ffmpeg\`\"`"
6 /c/Program Files/ffmpeg-20140916-git-b76d613-win64-static

2つ上までならなんとかなるけれど、3つ上指したくなったらと考えると頭痛くなってくる。どうなんだろな、「最新の *utils」とかだと追加のオプションとか出来てたりすんのかな、ただ「MSYS」な(bash builtin の)dirname は一階層しか上がれない。

一応 Unix の「(文字通り bash ですらない素の) bourne shell」スクリプトで書いた:

dirnamep
 1 #! /bin/sh
 2 PROG="`basename \"$0\"`"
 3 USAGE="\
 4 ${PROG} [-p count] path"
 5 
 6 GEN=1
 7 
 8 while test $# != 0
 9 do
10     case $1 in
11         -p)     test $# -lt 2 && { echo "$USAGE" 1>&2; exit 1; }
12                 GEN="$2";
13                 shift 2 ;;
14         -p*)    GEN="`echo $1 | sed s@^..@@`";
15                 shift ;;
16          *)     break
17     esac
18 done
19 
20 
21 RES="$1"
22 while test $GEN -ge 1
23 do
24     RES="`dirname \"$RES\"`"
25     GEN=`expr $GEN - 1`
26 done
27 echo $RES

(つーか「dirname」依存なこと自体、暗黙に bash を期待してはいるんだけれど、「builtin でない dirname」もないわけではないしね。)

今度はラクチン:

1 me@host: ~$ dirnamep "`type -p ffmpeg`"
2 /c/Program Files/ffmpeg-20140916-git-b76d613-win64-static/bin
3 me@host: ~$ dirnamep -p2 "`type -p ffmpeg`"
4 /c/Program Files/ffmpeg-20140916-git-b76d613-win64-static
5 me@host: ~$ dirnamep -p3 "`type -p ffmpeg`"
6 /c/Program Files
7 me@host: ~$

なんでシェルスクリプトで書いたかって? 「速度」が理由ではないよ。ただ別に python はお呼びでもないかなと思っただけ。