Git Bashで.batや.lnkを使うとき拡張子を省く


Git for Windows付属のBashは、Gitの動作に必要なためと思いますが、perlなどmsys由来のユーティリティがついてくるのがちょっと便利です。

ただ、msysはWindows上でUNIXっぽい環境を再現する物のためWindowsネイティブと噛み合わない部分があり、普段作業環境として使うにはコマンドプロンプトに比べて多少不便なことがあります。

  • バッチファイルを呼び出すときは./foo.batなど拡張子をつけてやらねばなりません。
  • ショートカットファイルを起動する時は、start ./foo.lnkのようにコマンドプロンプトを挟む必要があります。
  • 当然ながら(実行ファイルではないため)PATH検索も働きません。

(.exeだけは補完してくれるのですが、exeだけの特別扱いのようで、PATHEXTのように他の拡張子を足す方法は見当たりませんでした)

この点が馴染めずコマンドプロンプトから離れられなかったのですが、先日command_not_found_handleというものを知りました。

command_not_found_handle フックが使える

Bash 4.0以降では command_not_found_handle というフックがあり、この名前で関数を定義しておくとコマンドが見つからないときに呼び出されます。

この関数に拡張子が.bat.lnkのときの扱いを書いてやれば、毎度拡張子をつけずとも普通のコマンドっぽく使うことができます。

command_not_found_handle の定義例

.bashrcなどに追記
command_not_found_handle ()
{
    # 拡張子が書いてあったりパスを含んでいるようならスキップ
    if [[ $1 == *.* || $1 == */* ]]; then
        echo "$1: command not found"
        return 127
    fi

    # batやlnkの置いてある場所 (筆者の場合はこれで足りるが、複数ある場合はPATHをなんかしたほうがよいかも)
    local binbase=/c/local/bin/
    local name=$1
    shift

    # 優先順序はここの並べ方で決まるので好みに合わせて要調整
    if [[ -f ./$name.bat ]]; then
        exec "./$name.bat" "$@"
    elif [[ -f ./$name.lnk ]]; then
        start "./$name.lnk" "$@"
    elif [[ -f $binbase/$name.bat ]]; then
        exec "$binbase/$name.bat" "$@"
    elif [[ -f $binbase/$name.lnk ]]; then
        start "$binbase/$name.lnk" "$@"
    else
        echo "$name: command not found"
        return 127
    fi
}

# Git Bashで動作を確認しています。Cygwinではstartcygstartに置き換えればいけると思います。WSLは試していませんが、同様に調整が必要そうな雰囲気がします

参考リンク