第1回 バッチを使ってみよう! ~ プロローグ ~


こんにちは くろねこです。

以前の記事でちょっとだけ触れましたが、
くろねこは自称プログラマです(笑)

そんな、くろねこの経験に基づき、しっかり動くシステムを構築するための工夫をお伝えできればと思います。

どうなるかわかりませんが(無責任)

Windows系のマシンであれば、どこでも作成・実行することができる「バッチ」について、少しだけ、皆さんのお役に立てればとの思いに何回かに分けて記事を投稿させていただきます。

このシリーズのコンセプトは下記として進めたいと思います。
(講釈がちになりそうです・・・)

■ コンセプト ■

だから、とうすればいいの!
講釈なんかどうでもいいんだよ!

よくわかんなくても、貼り付ければ使える

そんな感じで投稿しますので。。。

途中、【講釈】と記載しているところは、時間のある時に読んでもらえれば、okです。

この記事の最後に、今回、説明する内容を盛り込んだサンプルのコードを掲載しています。テンプレートとしてご利用ください。

バッチとは【講釈】

さっそく「講釈」です。おいおい!
ここでいう「バッチ」とは、Windowsに実装されているバッチファイルのことです。(以降、バッチと記述させていただきます。)

「バッチ」というと、一括処理の「バッチ処理」という処理方法を思い浮かべる方はいるのではと思います。ちょっと古いですかね。。。
(昔の情報処理をご存じの方なら、オンラインとバッチ(夜間バッチ)ですね。)

この一括処理を、Windowsではバッチファイルとして作成・実行することができます。
ファイルの内容は、実行するコマンドを順番に記述したものですが、実行制御(判定による処理の分岐など)も可能です。
ちょっとした作業でも、何回も繰り返す作業の場合は、非常に有益な方法です。
バッチファイルの拡張子は「bat」や「cmd」で、インタプリタ(※)として動作します。

(※) インタプリタとは、実行時に記述内容を1行ずつ解釈しながら実行するプログラムのことでそのまま実行することができます。c言語のようなコンパイルマシン語への翻訳)は不要です。

必ずお読みください

バッチは、気軽 に作成できますが、記述するコマンドによっては、大惨事 を起こしてしまうので、注意が必要です。
特に、ファイルを更新したり、削除したりする作業です。

これまで、多くの事故現場に出くわしてきました。中には〇亡事故も目の当たりにしました。(事故現場とは、システムが〇んだという意味です。念のため・・・)

コンピュータは大量処理とその実行速度が取り柄ですので、壊れるのは一瞬なんです(怖)

【ご注意】
ここに記述する内容は、初期のMS-DOS時代から触れてきた、そして、作ってきた くろねこの経験からあみだしたものです。個人的な思いが大変強く出ていますが、何かの参考になればと思います。

また、本サイトを参考に作成したものは、自己責任でお願いします。
実行前のレビューやテストを必ず実施してください。
ナメてかかると大惨事に繋がりますので

メンテナンスしやすさを意識する

サクッと作れてしまうので、作るときはあまり意識しませんが、しばらく経ってから、環境の変化などにより、
・ バッチのフォルダを変更
・ バッチを別のマシンで実行
などの要望が発生し、バッチを修正しなければならなくなったときに、結構大変な思いをすることが多いと思います。

あとからだと、そのとき(作った時)の「思い」が分からず、解析に多くの時間がかかったり、苦労します。

ここでは、その「苦労」を少しでも軽減するための工夫です。

カレントフォルダ

目的

バッチ実行時に、実行フォルダをバッチがあるフォルダに変更するものです。

記述方法

cd /d %~dp0

これをバッチの冒頭に記述します。

解説【講釈】

バッチは、その処理でアクセスするファイルをどのように記述するかによって、汎用性という面が大きく変わります。
対象のファイルを、完全パス名(フルパス、絶対パスとも言います。)で書いてしまった場合、そのファイルは「不動」のものとなります。別のマシンで同じバッチを動かしたいが、ドライブやフォルダ構成が異なる場合、バッチを修正しなければなりません。修正したら、しっかり確認(テスト)しないと事故が起こるかもしれません。
ただ、別の環境で動かしたいだけですか、意外とリスクが大きいのです。

この環境の変化に伴う「手間」を少なくするために、アクセスするファイルは実行しているバッチがあるフォルダを基準とした「相対パス」で記述することです。
バッチがアクセスするファイルは、バッチがあるフォルダと同じか、それ配下(より深い)フォルダにまとめることです。

バッチが動作するときに、そのバッチがあるフォルダをカレントフォルダに変更すれば、そこからの相対パスでアクセスが可能となるわけです。

ある意味、バッチの「お約束事」としてください。

環境変数

目的

バッチの中で、可変な値を持たせたい場合に利用できる変数(情報の入れ物)のことです。
環境変数を利用することで、実行時に変化する値などを利用することができます。

記述方法

set 環境変数=値

代入記号の"="の前後にスペースを入れないようにします。

事前に環境変数の宣言は不要です。

set 環境変数=

環境変数は消滅します。

くろねこの場合、自分が使用する環境変数は"@"を付け、変数名は英大文字として、既存のものと区別するようにしています。
また、環境変数のスコープ(有効範囲)については、別の機会に触れたいと思います。

解説【講釈】

実行時に確実に変化するものといえば、実行日時です。
これらの情報を利用したい場合は、環境変数に実行日時を設定すればよいのです。

set @STARTDATE=%date% %time%

変数@STARTDATEに日付 時刻を設定した例になります。

変数に設定される値は、"="の直後からその行の末尾までです。
"="の右側(代入する値)は、"="の直後からとなります。
言葉だとわかりにくいので具体例をあげます。
set @AAA = ABC
set @BBB=ABC
実行後、変数@AAAと変数@BBBの内容は等しくないのです。
変数@AAAの値 → " ABC" (先頭に半角スペースが入る)
変数@BBBの値 → "ABC" 

ログファイル出力

目的

実行結果を記録するものです。無くても問題ありませんが、実際にどう動いたのかなどの記録として残しておくものです。
具体的には以下の部分でログを出力することをお勧めします。
① バッチ開始
② ラベル
③ コマンド実行
④ バッチ終了
また、ログファイル用のフォルダも一つ準備しましょう。

各名称は仮ですが次の通りで話を進めます。
(特別な理由がなければ、そのまま、お使いください。)

ログフォルダ : .\LOG (バッチのフォルダ配下)
ログファイル名 : yyyymmdd_hhmmss.log

記述方法

①バッチ開始

    rem ログフォルダ
    set @LOGFOLDER=.\LOG
    rem ログファイル名
    set @LOGFILE=%@LOGFOLDER%\%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%.log
    rem ログフォルダの準備
    if not exist %@LOGFOLDER% md %@LOGFOLDER% 
    rem バッチ開始ログ
    echo %0 started at %date% %time% > %@LOGFILE%

②ラベル

:label01
    rem ラベル
    echo label01 >> %@LOGFILE%

(ラベルは"label01"の場合)

③コマンド実行

    rem コマンド実行
    dir .\log\*.* >> %@LOGFILE%

(コマンドは"dir"の場合)

④ バッチ終了

    rem バッチ終了ログ
    echo %0 ended at %date% %time% >> %@LOGFILE%
    set @LOGFILE=
    set @LOGFOLDER=

解説【講釈】

ログ出力は、リダイレクトという機能を使ってファイルに出力します。
出力先のファイル名に日時を使うのは動作した日時ごとに記録を残すためです。

特にタスクスケジューラ等で自動実行する運用の場合には、後追いで動作記録を確認することが可能となります。

自動実行は大変便利ですが、それだけにきちっと動かないと意味がありません。
何が起きたか分からない では済まされません。

リダイレクトは、コマンドが画面(標準出力(※))に出力した情報を画面ではなく指定したリダイレクト先に出力する機能です。

"> 出力先" と記載した場合は、出力先に上書きされます。(上記①)
">> 出力先" と記載した場合は、出力先に追加書きされます。(上記②③④)
いずれも、出力先ファイルが存在しない場合、ファイルが作成され出力されます。

リダイレクトは標準出力の内容を出力先に出力するため、echoで画面表示した内容も可能です。
簡単に言えば、画面の代わりに指定されたファイルに出力するものです。

ただ、何でもかんでもリダイレクトすると、訳がわからないものなってしまいがちになりますので、必要最小限にしましょう。

くろねこの場合、
・ ラベル(分岐先)
 if文による分岐がある場合の動きを把握できる
・ 主要コマンドの実行結果
 コマンドの仕様に左右されますが、コマンドの実行結果は必ず出力しましょう。
・ 開始日時と終了日時
 バッチが、いつ起動されたのか、また、いつ終わったのか把握できます。
想定外の日時の実行や、動作に想定以上の時間が掛かってないかを確認できます。

ログファイル出力は、リダイレクト機能無しでは語れないくらいのものです。

(※)標準出力とは、ブログラムが画面にテキストメッセージを出力する際のデフォルトの出力先です。c言語の printf() やバッチの echo の出力先です。
どこにも出力しない場合は、nul を指定します。
ただし、標準出力に出力しないコマンドやプログラムもありますので、バッチに組み込む前に動作を確認してください。

終わりに

今回の内容は、「お作法」的なもので、くろねこの体には染み付いているものです。
とはいえ、入力ミスを避けるため、テンプレート化としています。

必要であれば、下記をコピペして、sample.bat などの名前で保存し、バッチ作成時のテンプレートとしてください。

rem ****************************************************************************
rem    バッチサンプル
rem ****************************************************************************

    rem カレントフォルダ変更
    cd /d %~dp0

    rem ログフォルダ
    set @LOGFOLDER=.\LOG

    rem ログファイル名
    set @LOGFILE=%@LOGFOLDER%\%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%.log

    rem ログフォルダの準備
    if not exist %@LOGFOLDER% md %@LOGFOLDER% 

    rem バッチ開始ログ
    echo %0 started at %date% %time% > %@LOGFILE%

:label01
    rem ラベル
    echo label01 >> %@LOGFILE%

    rem コマンド実行
    dir .\log\*.* >> %@LOGFILE%

:label02
    rem ラベル
    echo label02 >> %@LOGFILE%

    rem バッチ終了ログ
    echo %0 ended at %date% %time% >> %@LOGFILE%

    set @LOGFILE=
    set @LOGFOLDER=

それでも、失敗はつきものです。

だから、しっかり、レビューしてテストを実施しています。

バッチ=簡単に作れる

のように思ってる方、多いですよね。
だから、注意が必要なのです!

(チ○コが縮み上がるような事態に遭遇しないために・・・)


この記事を参考に、
初期コーディングの段階での
品質を少しでも高く
できればと思ってます。

今回は、バッチに関するとりかかり部分を投稿させていただきました。
不定期ではありますが、バッチ関連の記事を今後も投稿させていただきます。

それでは、また。


くろねこ自由気ままな日記

お時間のある方は、こちらの記事もご覧ください。

www.kuronekofreedom.com

ブログランキング・にほんブログ村へ
© 2020 くろねこ自由気ままな日記