【bat】Windowsのバッチファイル　ネタ帳

*.batに関するTipsです。

#日付時分秒の文字列を生成する。

例えば、ファイル名に日付時分秒を使いたい場合に利用できる。

```bat
rem -> 20161115 95654
set YMD=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%
rem -> 20161115095654
set YMD=%YMD: =0%
```

【解説】

ひとつ目の命令文だけだと、時が一桁の場合に空白が入り込む。
以下の例だとAM9時が" 9"となる。

```bat
rem -> 20161115 95654
set YMD=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%
```

" 9"のままだとマズいので、" "を"0"に置換する。

```bat
rem -> 20161115095654
set YMD=%YMD: =0%
```

#ファイル行数を変数に格納する
例えばインプットとなるファイルの件数によって処理を切り分ける場合などに利用できる。

以下の例では"C:\bat\data\sample.csv"のファイル行数をカウントし、LINECOUNTに格納している。

```bat
FOR /F "DELIMS=" %%A IN ('type C:\bat\data\sample.csv ^| find /c /v ""') DO SET LINECOUNT=%%A

rem 1などの件数が格納される。
echo %LINECOUNT%

```

留意点：ファイルの最終行（空行）はカウントされない。

#バッチファイルからSQL Serverに接続し、selectを発行して、CSVファイルを出力する

業務系だとこういうのよくあります。よくありすぎます。

```bat
rem 当日日付
set YYYYMMDD=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%

rem SQL実行 --------------------------------------------------------------
rem オプション
rem -S サーバー
rem -U ユーザー
rem -P パスワード
rem -d DB名
rem -w ファイル行の横幅 （当処理では50000）
rem -s 区切り文字
rem -W 項目毎の後ろスペース削除
rem -i sqlファイル
rem -o 出力ファイル
rem -h -1でヘッダー出力なし
rem -b エラー返却
rem ----------------------------------------------------------------------
sqlcmd -S db-server001\db -U user -P password -d production -w 50000 -s "," -W -i C:\bat\sql\dataOutput.sql -o C:\bat\data\dataOutput.csv -h -1 -b -v Param1=%YYYYMMDD%

rem エラーハンドリング
if not %ERRORLEVEL% == 0 (
  exit /b %ERRORLEVEL%
)
exit /b 0
```

上記例では、C:\bat\sql\dataOutput.sqlを実行して、C:\bat\data\dataOutput.csvを出力しています。
なお、引数として当日日付をSQLに引き渡しています。
もちろんC:\bat\sql\dataOutput.sqlは別途作っておく必要があります。
結構便利だと思っています。

ちなみにC:\bat\sql\dataOutput.sqlはこんな感じです。

```sql:dataOutput.sql
set nocount on;
declare @yyyymmdd varchar(8) = $(Param1); /* batからのパラメータ */

select * from xxx ...

```

#バッチでPDFファイルの内容の並び替えをする。(PDFtkが必要)

こんなことをする必要があるのかと疑問に思われるでしょうが、あります。残念ながら。
あるからには仕方がないのでバッチにしました。

なお、PDFtkというコマンドラインからPDFファイルを扱えるソフトが必要になります。もし利用する場合はライセンスなどを確認してください。

[PDFtkのダウンロードページ](https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/)


```bat
rem 1.base.pdfの1-144ページをprocessed_1.pdfとして出力する
pdftk base.pdf cat 1-144   output processed_1.pdf

rem 2.base.pdfの148-最終ページをprocessed_2.pdfとして出力する
pdftk base.pdf cat 148-end output processed_2.pdf

rem 3.base.pdfの145-147ページをprocessed_3.pdfとして出力する
pdftk base.pdf cat 145-147 output processed_3.pdf

rem 1-3で作成した3つのPDFファイルを結合する
pdftk processed_1.pdf processed_2.pdf processed_3.pdf cat output sorted.pdf
```

#データベースの定義などを設定ファイルから読み込む

バッチファイルであっても、共通化できる箇所は共通化しておきたい。というかすべきと思う。

なので、複数のバッチファイルで共通化できる部分はsetting.batというファイルを作り、そこに定義する。

【設定ファイル】

```bat:setting.bat
rem 接続先DBを設定
set DBNAME=TEST_DB
```

【バッチファイル】

```bat
rem setting.batを実行し、変数をセットする。
rem setting.batは当ファイルと同一ディレクトリ配置する。
CALL setting.bat
echo %DBNAME% -> TEST_DB
```

たかがバッチファイルだけれど、メンテナンスし易いようにしておきたい。

#ログファイルの出力
当たり前ですが、ログを出力しておくと障害時などに活用できます。

```bat:test.bat
@echo off

rem バッチファイルが配置されたディレクトリに移動
cd /d %~dp0

rem バッチファイル名を取得
set BAT_NAME=%0

rem YYYYMMDDHHMISSを取得
set YMD_TIME=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%
set YMD_TIME=%YMD_TIME: =0%

rem ログを配置するディレクトリとファイル名
rem ログディレクトリ（このバッチファイルの配置場所の直下にlogというディレクトリがある）
set LOG_DIR=log\
rem ログファイル -> バッチファイル名_YYYYMMDDHHMISS.log
set LOG_FILE=%LOG_DIR%%BAT_NAME%_%YMD_TIME%.log

rem ======================================================================
rem 初期処理
rem ======================================================================
call :Log "初期処理開始"

rem 初期処理が記載されているとする。

call :Log "初期処理終了"

rem ======================================================================
rem メイン処理
rem ======================================================================
call :Log "メイン処理開始"

rem メイン処理が記載されているとする。

rem エラーハンドリング
if not %ERRORLEVEL% == 0 (
  call :Log "メイン処理異常終了"
  call :Log "リターンコード＝%ERRORLEVEL%"
  exit /b %ERRORLEVEL%
)

call :Log "メイン処理終了"

rem ======================================================================
rem 終了処理
rem ======================================================================
call :Log "終了処理開始"

rem 終了処理が記載されているとする。

call :Log "終了処理終了"

exit /b 0

rem ======================================================================
rem 個別処理
rem ======================================================================

rem ログ出力
:Log
  echo %DATE% %TIME% %BAT_NAME% %~1>> %LOG_FILE%
  exit /b 0

```

実行結果
>C:\bat>test.bat
>
>C:\bat>cd log
>
>C:\bat\log>type test.bat_20161116153856.log
>2016/11/16 15:38:56.09 test.bat 初期処理開始
>2016/11/16 15:38:56.09 test.bat 初期処理終了
>2016/11/16 15:38:56.10 test.bat メイン処理開始
>2016/11/16 15:38:56.10 test.bat メイン処理終了
>2016/11/16 15:38:56.12 test.bat 終了処理開始
>2016/11/16 15:38:56.12 test.bat 終了処理終了

ポイントはログ出力処理をfunction化（実際はGOTO文を使っているだけ）しておくこと。
実際に運用するにあたっては、もう少し情報が必要だと思う。

このログについては、もっといい方法があるのかも知れない。
さらっと作っただけなので、もしいい方法があれば教えて下さい。


***


今後追記していく。予定。