1. 無料アクセス解析
PGKissUNIXライクなパス操作をwindowsのcmd.exeのバッチファイルのみで実現 2009/5/31

UNIXライクなパス操作をwindowsのcmd.exeのバッチファイルのみで実現 2009/5/31

Windows 2000, XP, Vistaには、cmd.exe(コマンドプロンプト)というCUI(キャラクタ・ユーザー・インターフェース)ベースのプログラムが付いている。バッチファイル(拡張子".bat")は、このプログラムによって実行される。 cmd.exeは、cscript.exeやwscript.exeと並んで、Windowsで処理を自動化する際の強い味方だ。

cmd.exeは、最初のころはあまり高機能でなく、込み入った処理に使うのは向かなかったが、コマンド プロセッサ拡張機能のバージョン(環境変数%CMDEXTVERSION%で確認できる)が2以上であれば、そこそこ便利に利用できる。

UNIXのシェル(sh, bash等)には及ばないものの、cmd.exeで手軽にできる範囲をまとめてみた。

関数(プロシージャ)の作成

これまで、ある程度以上複雑なパッチファイルを読みやすく書くのは困難だった。バッチファイルでは、基本的に制御をgoto文でバッチファイルのあちこちに飛ばすことで処理フローを記述してきた。いわゆるgoto文によるスパゲッティプログラムになりがちだった。

goto文の拡張や、call文の拡張で、多少不格好ではあるが関数(プロシージャ)が書けるようになった。これで、バッチファイルを構造化するのが容易になった。
以下に使い方を示す。

call :ラベル [引数1] [引数2] ...

で「ラベル」でマークされた関数を呼び出し、

goto :EOF

で関数からリターンする(トップレベルでこれを実行した場合、バッチファイルの実行を終了する)。 call文で渡した引数は、関数内で%1, %2等として参照できる。 下記は、バッチファイル版のechoコマンドだ。

@echo off

if not CMDEXTVERSION 2 (
	echo cmd.exeのバージョンが古い
	goto :EOF
)

set progName=%0
if "%1" == "" (
	rem 関数呼び出し
	call :usage
	goto :EOF
)

echo %*
goto :EOF

rem 関数定義
:usage
	echo Usage: %progName% 引数1 [引数2] [引数3] ...
	echo 引数を標準出力に出力する。
	goto :EOF

パス関連情報の操作

%~で始まるバッチパラメータの置換が拡張されたためパスの操作が比較的簡単になった。これを利用するとUNIXのdirnameやbasename,whichコマンドなどに相当する機能を実現できる。バッチパラメータ置換の拡張の使い方は、コマンドプロンプトで下記のように入力すると確認できる。

call /?
...前略
    バッチ パラメータ (%n) の置換は拡張されました。次のオプション構文
    を使うことができます:

        %~1         - すべての引用句 (") を削除して、
                      %1 を展開します。
        %~f1        - %1 を完全修飾パス名に展開します。
        %~d1        - %1 をドライブ文字だけに展開します。
        %~p1        - %1 をパスだけに展開します。
        %~n1        - %1 をファイル名だけに展開します。
        %~x1        - %1 をファイル拡張子だけに展開します。
        %~s1        - 展開されたパスは、短い名前だけを含みます。
        %~a1        - %1 をファイル属性に展開します。
        %~t1        - %1 をファイルの日付/時刻に展開します。
        %~z1        - %1 をファイルのサイズに展開します。
        %~$PATH:1   - PATH 環境変数に指定されているディレクトリを
                      検索し、最初に見つかった完全修飾名に %1 を
                      展開します。環境変数名が定義されていない場合、
                      または検索してもファイルが見つからなかった
                      場合は、この修飾子を指定すると空の文字列に
                      展開されます。

    修飾子を組み合わせて、複合結果を得ることもできます:

        %~dp1       - %1 をドライブ文字とパスだけに展開します。
        %~nx1       - %1 をファイル名と拡張子だけに展開します。
        %~dp$PATH:1 - PATH 環境変数に指定されているディレクトリを
                      検索して %1 を探し、最初に見つかったファイル
                      のドライブ文字とパスだけに展開します。
        %~ftza1     - %1 を DIR の出力行のように展開します。
...後略

標準出力を変数へ

UNIXでは、コマンドの実行結果をバッククォートで変数に簡単に代入できる。しかし、バッチファイルではそれができない。と思ったら、意外な方法でできる。for文に/fオプションをつけることで実現できる。詳しくはコマンドラインで下記のように入力すればよい。

for /?

下記は日付を取得してそれをファイル名として利用する例だ。

@echo off
for /f %%i in ('date /t') do (
	set date=%%i
)
set logfile=AppLog-%date:/=-%.log
someApplication > %logfile%

下記は、UNIXライクなコマンドを実現する。unix.batだ。

@echo off

if not CMDEXTVERSION 2 (
	echo cmd.exeのバージョンが古い
	goto :EOF
)

setlocal
set cmd=%1
shift
rem %*がshiftされないので
call :%cmd% %1 %2 %3 %4 %5 %6 %7 %8 %9
if defined _RESULT_ echo %_RESULT_%

endlocal
goto :EOF

:fullpath
	rem 第一引数をフルパスで返す。
	set _RESULT_=%~f1
	goto :EOF

:dirname
	rem 第一引数で指定されたディレクトリまたはファイルを含むディレクトリを返す。
	rem 末尾に\が付いている。Ex. C:\temp\, C:\
	set _RESULT_=%~dp1
	goto :EOF

:which
	rem PATHの中から第一引数で指定されたファイルに最初に一致するものを返す。
	rem 拡張子(環境変数PATHEXTで指定されたもの)を自動的に補完しないので、"cmd.exe"のように拡張子も含めて指定すること。
	set _RESULT_=%~$PATH:1
	if not defined _RESULT_ echo PATHに%1は存在しません
	goto :EOF

:basename
	rem 第一引数からドライブレター、パスを取り除きファイル名(ディレクトリ名)のみを返す。
	set _RESULT_=%~nx1
	if ""=="%2" goto :EOF
	if "%~x1"=="%2" set _RESULT_=%~n1
	goto :EOF

:read
	rem 入力された文字列を第一引数で指定した変数に格納する。
	set /p %1=
	goto :EOF

:ls
	rem ファイル名の一覧を標準出力へ出力する。
	dir /B %1
	goto :EOF

inserted by FC2 system