シェルスクリプト自身のパスを取得しようとしたらdirnameが無かったので頑張った話

シェルスクリプトを書いていて、実行時にそのスクリプト自身のパスを取得したくなった。バッチファイルでいうコレみたいな感じ。

@echo off
echo %~dp0

そのスクリプト環境変数PATHに登録されたディレクトリに置くことはなく、必ずカレントディレクトリから相対パスないし絶対パスで指定して実行する。取得するパスは相対パスで構わない。

よくある方法はこんな感じだと思う。

#!/bin/sh

# 相対パスでも問題ない場合
echo `dirname $0`

# 確実に絶対パスで取得したい場合
echo `cd \`dirname $0\`; pwd`

で、その方法を使おうとしたらdirname(1)が無くて駄目だった……恐るべし組込みLinux

幸いなことに組み込んであるbusyboxにてawk(1)とbasename(1)が有効になっていたので、こんな感じで逃げてみた。

#!/bin/sh

echo `echo "$0" | awk '{ print substr($0, 1, index($0, "'\`basename $0\`'") - 2) }'`

但しスクリプト名と同名のディレクトリ等がパスに含まれていたら駄目なはず。

後で頭を捻って、最終的に導き出した方法がこれ。

#!/bin/sh

echo `echo "$0" | awk '{ print substr($0, 1, length($0) - length("'\`basename $0\`'") - 1) }'`

文字列を比較するのではなく、出力してもよい文字列長を求めてみた。

これを汎用化してdirname(1)の代用品を作ろうとすると色々と面倒そうだ。

  • 例えば「./foo」ではなく「foo」と指定された場合への対応。
  • 例えば「/foo/bar」ではなく「/foo/bar/」と指定された場合への対応。

なので止めておいた。