すごいDOSバッチ　（コピペで）たのしく逃げよう！

「DOSバッチファイル」、嫌な響きですね...。

DOSバッチの作成依頼は、心の準備をしていないときに突然降って湧くもので、毎回毎回、`for`文の書き方をググってはハマり、環境変数の即時展開でハマり、「`(の使い方が誤っています`」「`0の使い方が誤っています`」等の言葉足らずのエラーに苦しめられる。こんな思い、二度としたくない。

でもいまさらDOSバッチの勉強なんてしたくない。

そんな時に備えて、DOSバッチでよく使うコードスニペットを用意しておきました。華麗にコピペで逃げましょう。

文字列操作等は関数化しています（結果の文字列は関数と同名の変数に格納されます）。勢いに乗って、Python的な文字列スライス関数（`Slice`）も作成しました。

```bat:バージョン情報
C:\>ver

Microsoft Windows [Version 6.1.7601]
```

```bat:コピペで逃げよう
@echo off
setlocal
rem ============================================================
rem 
rem main
rem 
rem ============================================================
rem このバッチファイルのカレントディレクトリへ移動
cd /d "%~dp0"

rem -------------------------------------------------------------
rem 前処理
rem -------------------------------------------------------------
rem バッチファイル名（拡張子つき）の取得
set prog_name="%~nx0"
echo %prog_name%を起動しました。

rem バッチファイル自身のフルパス（例：「C:\bat\sample.bat」）
set target_file="%~f0"
rem バッチファイルの格納先ディレクトリ（例：「C:\bat\」）
set target_dir="%~dp0"

rem ファイルの存在チェック
call :FileExist "%target_file%"
if %ERRORLEVEL% equ 1 (
    echo ファイル（%target_file%）が見つかりました。
) else (
    echo ファイル（%target_file%）が見つかりません。
    exit /b 1
)

rem ディレクトリの存在チェック
call :DirExist "%target_dir%"
if %ERRORLEVEL% equ 1 (
	echo ディレクトリ（%target_dir%）が見つかりました。
) else (
    echo ディレクトリ（%target_dir%）が見つかりません。
	exit /b 1
)

rem -------------------------------------------------------------
rem みんなに愛されてないFor文
rem -------------------------------------------------------------
rem 単語のイテレーション
for %%a in (aaa bbb ccc) do (
    set x=%%a
    call echo %%x%%
)

rem 整数のイテレーション
for /l %%a in (1,1,10) do (
    set x=%%a
    call echo %%x%%
)

rem ファイルのイテレーション
for %%a in (*.bat) do (
    set x=%%a
    call echo %%x%%
)

rem ファイルのイテレーション（サブディレクトリも再帰的に検索）
for /r %%a in (*.bat) do (
    set x=%%a
    call echo %%x%%
)

rem ディレクトリのイテレーション
for /d %%a in (*) do (
    set x=%%a
    call echo %%x%%
)

rem ディレクトリのイテレーション（サブディレクトリも再帰的に検索）
for /d /r %%a in (*) do (
    set x=%%a
    call echo %%x%%
)

rem CSVファイルの行イテレーション（各行のフィールド値をa,b,cに割り当て）
for /f "tokens=1-3 delims=," %%a in (sample.csv) do (
    echo [%%a %%b %%c]
)

rem コマンド実行結果の取得（例：CSVファイルの行数の取得）
set CMDSTR="type sample.csv | find /c /v """
for /f "usebackq delims=" %%a in (`%CMDSTR%`) do (
    set lines=%%a
)
echo %lines%

rem ファイル情報の取得
call :GetFileInfo .\sample.bat
echo %GetFileInfo.FileName%
echo %GetFileInfo.DirName%
echo %GetFileInfo.UpdateDate%

rem 数字列かの判定
call :IsNumeric 2147483647
echo IsNumeric 2147483647 =^> %ERRORLEVEL%
call :IsNumeric 214x483647
echo IsNumeric 214x483647 =^> %ERRORLEVEL%
call :IsNumeric -214x483647
echo IsNumeric -214x483647 =^> %ERRORLEVEL%

rem -------------------------------------------------------------
rem 文字列操作
rem -------------------------------------------------------------
echo ==== 文字列操作 ==================
rem 部分文字列の切り出し
call :SubStr abcdef 2 3
echo SubStr abcdef 2 3 =^> %SubStr%

rem 部分文字列の置換
call :Replace abcdef cde CDE
echo Replace abcdef cde CDE =^> %Replace%

rem 文字列の反転
call :Reverse ABCDEF
echo Reverse ABCDEF =^> %Reverse%

rem 小文字→大文字変換
call :UpCase abcdefg
echo UpCase abcdefg =^> %UpCase%

rem 大文字→小文字変換
call :DownCase ABCDEFG
echo DownCase ABCDEFG =^> %DownCase%

rem 文字列のスライス（インタフェース仕様はPythonと同じ）
call :Slice 123456789 "" "" -1
echo Slice 123456789 "" "" -1 =^> %Slice%

rem -------------------------------------------------------------
rem 年月日の取得
rem -------------------------------------------------------------
call :GetYear & call :GetMonth & call :GetDay & call :GetHour & call :GetMin & call :GetSec
echo GetYear ^(%DATE% %TIME%^) -^> [%GetYear%,%GetMonth%,%GetDay%,%GetHour%,%GetMin%,%GetSec%]

endlocal

exit /b 0

rem ============================================================
rem 
rem プロシージャ群
rem 
rem ============================================================
rem ============================================================
rem FileExist - ファイルの存在チェック(UNCパス/NFSパスにも対応)
rem ============================================================
:FileExist
    if exist "%1" (
        if not exist "%1\*" (
            exit /b 1
        )
    )
    exit /b 0

rem ============================================================
rem DirExist - フォルダの存在チェック(UNCパス/NFSパスにも対応)
rem ============================================================
:DirExist
    if exist "%1\*" (
        exit /b 1
    )
exit /b 0

rem ============================================================
rem GetFileInfo - ファイルの情報
rem ============================================================
:GetFileInfo
	set GetFileInfo.FilePath=%1

	for %%a in (%GetFileInfo.FilePath%) do (
		set GetFileInfo.FileName=%%~nxa
		set GetFileInfo.FileNameNoExt=%%~na
		set GetFileInfo.ExtName=%%~xa
		set GetFileInfo.DirName=%%~dpa
		set GetFileInfo.UpdateDate=%%~ta
		set GetFileInfo.FileSize=%%~za
	)
exit /b 0

rem ==============================================
rem StrLen - 文字数のカウント
rem ==============================================
:StrLen
	set _target=%1
	set _cou=0

	if not defined _target (
	    set StrLen=0
	    exit /b 0
	)

:__STRLEN_START__
	call set _target=%%_target:~1%%
	set /a _cou+=1
	if defined _target (
		goto __STRLEN_START__
	)

    set StrLen=%_cou%
exit /b 0

rem ============================================================
rem SubStr - 文字列の切り出し（0オリジン）
rem ============================================================
:SubStr
	set SubStr._target=%1
	set SubStr._start=%2
	set SubStr._length=%3
	call set SubStr=%%SubStr._target:~%SubStr._start%,%SubStr._length%%%
exit /b 0

rem ============================================================
rem Replace - 文字列置換（0オリジン）
rem ============================================================
:Replace
	set Replace._target=%1
	set Replace._old=%2
	set Replace._new=%3
	call set Replace=%%Replace._target:%Replace._old%=%Replace._new%%%
exit /b 0

rem ============================================================
rem Slice - 文字列スライス（インタフェース仕様はPythonと同じ）
rem ============================================================
:Slice
	set Slice._target=%1
	set Slice._start=%~2
	set Slice._end=%~3
	set Slice._step=%~4
	if not defined Slice._target (
		exit /b 0
	)

	call :StrLen %Slice._target%
	set /a Slice._target_len=%StrLen%

	rem ---------------------------------------
	rem デフォルト値の設定
	rem ---------------------------------------
	rem ステップ
	if not defined Slice._step (
		set /a Slice._step = 1
	)

	rem スタート・エンド
	if %Slice._step% geq 0 (
		if not defined Slice._start (
			set /a Slice._start = 0
		)
		if not defined Slice._end (
			set /a Slice._end = Slice._target_len
		)
	) else (
		if not defined Slice._start (
			set /a Slice._start = Slice._target_len - 1
		)
		if not defined Slice._end (
			set /a Slice._end = Slice._target_len * -1 - 1
		)
	)

	rem ---------------------------------------
	rem スタート・エンドが負の数→正の数に変換
	rem ---------------------------------------
	if %Slice._start% lss 0 (
		set /a Slice._start += Slice._target_len
	)
	if %Slice._end% lss 0 (
		set /a Slice._end += Slice._target_len
	)
	rem ---------------------------------------
	rem エンドの調整
	rem ---------------------------------------
	if %Slice._step% geq 0 (
		set /a Slice._end -= 1
	) else (
		set /a Slice._end += 1
	)

	set Slice._target_sliced=

	for /l %%a in (%Slice._start%,%Slice._step%,%Slice._end%) do (
		call set Slice._target_char=%%Slice._target:~%%a,1%%
		call set Slice._target_sliced=%%Slice._target_sliced%%%%Slice._target_char%%
	)

	set Slice=%Slice._target_sliced%

exit /b 0

rem ============================================================
rem Reverse - 文字列反転
rem ============================================================
:Reverse
	set Reverse._target=%1
	if not defined Reverse._target (
		exit /b 0
	)

	call :StrLen %Reverse._target% & set /a Reverse._target_len=%StrLen%-1
	set Reverse._target_rev=

	for /l %%a in (%Reverse._target_len%,-1,0) do (
		call set Reverse._target_char=%%Reverse._target:~%%a,1%%
		call set Reverse._target_rev=%%Reverse._target_rev%%%%Reverse._target_char%%
	)

	set Reverse=%Reverse._target_rev%

exit /b 0

rem ============================================================
rem DownCase - 大文字→小文字変換
rem ============================================================
:DownCase
	set DownCase._target=%1
	for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
		call set DownCase._target=%%DownCase._target:%%a=%%a%%
	)
	set DownCase=%DownCase._target%
exit /b 0

rem ============================================================
rem UpCase - 小文字→大文字変換
rem ============================================================
:UpCase
	set UpCase._target=%1
	for %%a in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do (
		call set UpCase._target=%%UpCase._target:%%a=%%a%%
	)
	set UpCase=%UpCase._target%
exit /b 0

rem ============================================================
rem IsNumeric - 数字のみかの判定
rem ============================================================
:IsNumeric
	set IsNumeric._target=%~1

	if %IsNumeric._target:~0,1%==- (
		call set IsNumeric._target=%%IsNumeric._target:~1%%
	)

	for /l %%i in (0,1,9) do (
		call set IsNumeric._target=%%IsNumeric._target:%%i=%%
		if not defined IsNumeric._target (
			exit /b 1
		)
	)

	if not defined IsNumeric._target (
		exit /b 1
	)
exit /b 0

rem ============================================================
rem GetYear - 年の取得
rem ============================================================
:GetYear
	set GetYear=%DATE:~0,4%
exit /b 0

rem ============================================================
rem GetMonth - 月の取得
rem ============================================================
:GetMonth
	set GetMonth=%DATE:~5,2%
exit /b 0

rem ============================================================
rem GetDay - 日の取得
rem ============================================================
:GetDay
	set GetDay=%DATE:~8,2%
exit /b 0

rem ============================================================
rem GetHour - 時の取得
rem ============================================================
:GetHour
	set GetHour=%TIME:~0,2%
	set GetHour=%GetHour: =0%
exit /b 0
rem ============================================================
rem GetMin - 分の取得
rem ============================================================
:GetMin
	set GetMin=%TIME:~3,2%

rem ============================================================
rem GetSec - 秒の取得
rem ============================================================
:GetSec
	set GetSec=%TIME:~9,2%
exit /b 0
```