プロジェクト

全般

プロフィール

Windowsバッチファイル

Windows OSが標準搭載する、コマンドを組み合わせてスクリプト実行する環境は、MS-DOS時代からのバッチファイル、WSH、PowerShellの3つです。
CUI(コマンドプロンプト)環境で使うならバッチファイルになると思います。

逆引きバッチ処理

バッチの起動・終了

バッチ起動時にコマンドプロンプトを最小化させる

ショートカットからバッチファイルを起動するときは、ショートカットのプロパティで実行時の大きさ欄を[最小化]に設定しておくとバッチファイル起動時に開くコマンドプロンプトがタスクバーに格納された状態となります。
ショートカットなしにバッチファイルを起動したときに、コマンドプロンプトをタスクバーに格納された状態にするには、次のようにバッチファイルの先頭に記述します。

@echo off
if not "%~0"=="%~dp0.\%~nx0" (
  start /min cmd /c,"%~dp0.\%~nx0" %*
  goto :eof
)

ウィンドウアプリケーション(GUI)を起動後、コマンドプロンプトを終了させる

GUIを持つウィンドウアプリケーションを起動するバッチファイルでは、ウィンドウアプリケーションが終了するまでコマンドプロンプトが開いたままとなります。
先の方法で最小化しておく方法もありますが、タスクバーにコマンドプロンプトが残ったままです。そこで、ウィンドウアプリケーションを起動したらコマンドプロンプト(バッチファイル)を終了させるには、次のように記述します。

start "" /b hello-gui one two

startに続く""はタイトルを指定するオプションで、/bでは不要ですが空文字列を指定しておかないと続くコマンドがうまく解釈されません。

バッチファイルの処理を終了させる

exit /b 1

戻り値を1としてバッチファイルを終了させます。
GOTO :EOF

暗黙のラベルEOFはバッチファイルの最後を意味します。GOTO文で指定するとき、コロンは他のラベルとは違い必須です。

コメントを書きたい

  1. 行の先頭にrem
    rem コメントだよ
  2. 行の先頭に::
    :: コメントだよ(実はラベル)

    ラベル(GOTO文の飛び先等)は行頭にコロン1つですが、コメントであることを規約的に明示するために2つコロンを並べています。

バッチのコマンドライン引数

バッチファイルのコマンドに引数を指定し、それを取得して処理を変える等に利用することができます。
バッチファイルを実行するコマンドラインに指定した引数は最大9個まで、次の変数に格納されています。

%1 %2 %3 %4 %5 %6 %7 %8 %9

10個以上コマンドラインに引数を指定した場合は、%1を処理したあとに@shiftを実行することで、%2が%1へ、%3が%2へと順に一つずつずらされます。
必要に応じて引数を取り出しながら@shiftを実行していきます。

また、%* とするとコマンドライン引数全体を取ることができます。(まとめて一つの文字列として取れる?)

バッチのコマンドラインの引数は、空白文字だけでなく、=;,も引数の区切りとして扱われます。

ファイル・ディレクトリ操作

バッチファイルの存在するディレクトリをカレントディレクトリにしたい

cd /d %~dp0
  • %0 が実行されたバッチファイルのフルパス(ダブルクォートで囲われた文字列)
  • ~ がダブルクォートを除去
  • d はドライブ文字だけ取り出し
  • p はパス(ドライブ文字およびファイル名を除いた文字列)
注) shiftを使うと以降%0が変わってしまう

shiftを使ってコマンドライン引数をずらすと、以降 %0 もずれてしまうので %~dp0 が意図しないものになってしまいます。
回避策は、shift /1 とします。

ファイルが実在するか調べたい

if exist "C:\Program Files\Foo" goto FOO_EXISTS
   | 中略
:FOO_EXISTS
   echo "あったよ" 
  • if not exist も使えます。

goto文を使わない

if exist "C:\Program Files\Foo" (
    echo "あったよ" 
) else (
    echo "なかったよ" 
)

ファイル(ディレクトリ)名を変更したい

renameコマンド(省略形 ren)を使います。

D:\work> ren read.txt readme.txt

注意点は第2引数で、ドライブ・パス名は付与せず変更後のファイル名(ディレクトリ名)のみを指定します。

D:\work> ren src\main java

これは、D:\work\src\main\ を、D:\work\src\java に変更します。

ファイルの数を数えたい

set num=0
for %%f in (data\*.dat) do (
    set /a num+=1
)
echo ファイル数は、%num%

for文で、処理対象ファイルをワイルドカードで複数指定しています。(data\*.dat)
該当するファイル名が入る変数はアルファベット1文字の制約があります。%%f
数を数えるカウンタとする変数は、数値として計算するのでset /aと右辺を数値で扱うようにしています。

ファイル・ディレクトリを圧縮したい

ファイルまたはディレクトリをzipで圧縮したい場合、Windows標準の手段としてはPowerShellのCompress-Archiveコマンドをバッチから呼び出します。

powershell compress-archive source/file target/file.zip

環境変数

バッチファイル内でのみ有効な変数を使いたい

setlocal
set FOO=abc
  :
endlocal
echo %FOO%  <--- 未定義エラー

変数をクリアしたい

T.B.D.

変数の文字列を置換したい

set BAR=%FOO:ab=AB%

変数の文字列の部分文字列を取り出したい

次の書式で、変数の文字列の部分文字列が取り出せます。

%変数名:~開始位置,文字数%

TEXT=AlfaBravo

指定例 結果例 備考
TEXT:~0,4 Alfa 文字の位置は先頭が0
TEXT:~,4 Alfa 開始位置を省略すると先頭(0)から
TEXT:~4,5 Bravo
TEST:~4 Bravo 文字数を省略すると最後まで
TEXT:~3,4 aBra

コマンド実行結果を変数に代入したい

C:\> for /f %i in ('dir /A-D /B /S %APPDATA%\NetBeans ^| findstr checkstyle.jar') do set CHECKSTYLE_JAR=%i
  • /fオプションはトークンを代入する繰り返し構文です。トークンオプションを指定していないので in 句の文字列をすべて変数に代入し1回だけ実行します。
  • バッチファイル中に記述するときは、%i を%%iと記述します。
  • コマンドライン中に、パイプ記号、リダイレクト記号、ダブルクォート、シングルクォートを使うときは、^でエスケープします。

数式の計算結果を変数に代入したい

set x=3
set /a y=%x%*2

/aオプションを付けると、右辺を数式として計算した結果を左辺の変数に代入します。
/aオプションがないと、右辺は文字列として左辺に代入されます(この例では、3*2が変数y)。

ファイルの内容を変数に代入したい

ファイルが1行のときは、次のコードで変数にファイル内容を代入します。

set /p FIRST= < data.txt
  • /pオプションはユーザー入力を変数に代入するオプションで、リダイレクトと組み合わせてファイルから変数に代入しています。

ファイルが複数行(既知の行)であれば次のように代入します。

(
    set /p FIRST=
    set /p SECOND=
    set /p THIRD=
)< data.txt

ファイルが複数行(可変長)であれば for文を使って読み込みます(別途記載)。

文字列処理

文字列を比較したい

if "%1"=="alfa" goto ALFA

ファイル内の文字列を置換したい

setlocal enabledelayedexpansion
for /f "delims=" %%I in (input.txt) do (
    set line=%%I
    echo !line:abc=ABC!>> output.txt
)
endlocal
  • 遅延環境変数の展開を有効化します
    でないと、forの処理で最後の行だけが有効になってしまうためです。
    遅延環境変数はコマンド実行時に展開されますが、通常の環境変数は解析時に展開されます。
    遅延環境変数は、%foo%ではなく!foo!で示します。

変数の文字列置換を使用しています。%変数名:置換元=置換後% で変数の文字列の中に含まれる置換元文字列が置換後文字列に置換された文字列が得られます。

ファイルの先頭一行を除きたい

set outfile=result.csv
for /f "tokens=* skip=1" %%l in (original.csv) do (
    echo %%l>>%outfile%
)
  • for /f で対象ファイルの内容を行単位でループ処理します。
  • tokensで各行の文字列を一括で変数に取り込みます(ここでは変数lに)。
    tokens=1,3 とすると、各行のデリミタで区切られた文字列の1番目と3番目を変数に取り込みます(変数は2個指定する)。
  • skip=1で先頭1行が対象外となります。
  • 行全体を変数outfileのファイルに追記します。
複数のCSVファイルを1つのCSVファイルに結合する

複数のCVSファイルを1つのファイルに結合します。ただし、各ファイルの先頭行には項目名の行があり、結合後はファイル先頭にのみ項目名の行を残すものとします。

文字列をコンソールへ表示させたい

echo こんにちは、バッチファイルです。
  • 次の記号を文字として表示させるには、^を使ってエスケープが必要です。
    < > | & ^


    echo 書式: copy ^<コピー元^> ^<コピー先^>

エラー処理

コマンド実行結果が成功か失敗かを判別したい

copy xxx yyy
if ERRORLEVEL 1 goto FAIL

イベントログ

イベントログに出力したい

eventcreate /id 593 /l application /so MY-BATCH /t SUCCESS /d "My batchの実行に成功" 

eventcreateコマンドでイベントログを発生させることができます。

  • idは、0~1000の範囲から指定
  • lは、イベント種類を指定。application、system等
  • soは、イベント発生源(ソース)の文字列を指定。省略時はeventcreateが適用
  • tはイベント種類を指定。SUCCESS、ERROR、WARNING、INFORMATION
  • dは説明


ほぼ4年前に更新