読者です 読者をやめる 読者になる 読者になる

bashのシェルスクリプトでexpand_pathとかを実装してみた

GroovyServで欲しくなったので実装してみたんですが、こんなまどろっこしい方法しかないのでしょうかね。

どっかに素敵な車輪が転がっているのかしら。


Linuxでは普通なGNU readlinkの-f, -e, -mオプションが使えれば話は早いんですけど、Mac OS XBSD系のreadlinkコマンドにはそんな素敵なオプションは用意されてません。
Rubyのexpand_pathとか魅力的なんですけど、できるだけ標準のシェルスクリプトの範囲で実現しておきたいわけです。


ということで、貧弱readlinkの機能範囲でパスを絶対パスに展開する関数を書いてみました。

resolve_symlink() {
    local TARGET=$1

    # if target is symbolic link
    readlink $TARGET >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        local ORIGINAL_FILEPATH=`readlink $TARGET`

        # if original is specified as absolute path
        if [ $(echo $ORIGINAL_FILEPATH | cut -c 1) = "/" ]; then
            echo "$ORIGINAL_FILEPATH"
        else
            echo "$(dirname $TARGET)/$ORIGINAL_FILEPATH"
        fi
    else
        echo "$TARGET"
    fi
}
expand_path() {
    local TARGET=$1
    if [ -d "$TARGET" ]; then
        echo $(cd $TARGET && pwd -P)
    elif [ -f "$TARGET" ]; then
        local TARGET_RESOLVED=$(resolve_symlink $TARGET)
        local FILENAME=$(basename $TARGET_RESOLVED)
        local DIR_EXPANDED="$(expand_path $(dirname $TARGET_RESOLVED))"
        echo "$DIR_EXPANDED/$FILENAME"
    else
        echo "$TARGET"
    fi
}

とりあえず、上のコードを丸々コピーしてbashのプロンプトに貼り付けると、

$ expand_path /tmp/../tmp/hoge
/private/tmp/hoge

こんな感じで相対パスだろうが、..を使ったパス記法だろうが、シンボリックリンクだろうが、実体としての絶対パスに展開されます。されるはず。のつもり。


バグ指摘、添削指導などあれば、是非お願いします。

あと、これのWindowsのBAT版とか書ける人いたら、是非ご教授願いたく。