バッチファイルの for /f で実行したコマンドのエラーを検出する
課題
バッチファイルで、コマンドの実行結果を変数に保存(キャプチャ) したいときに for /f コマンドがしばしば用いられます。
次のような使い方ですね。
for /f "usebackq delims=" %%i in (`dir /b`) do echo Value: %%~i
ただ、コマンド(ここでは dir コマンド) が正常に終了する場合は、このような記載で問題ないのですが、多くのコマンドはたまに失敗することがあります。
例えば、下記のようなバッチファイルを実行してみます。
HOGE は存在しないファイルとします。dir コマンドは存在しないファイルを表示する場合に失敗します。
@echo off for /f "usebackq delims=" %%i in (`dir /b HOGE`) do echo Value: %%~i
実行結果です。
ファイルが見つかりません
標準エラー出力にエラーが出力されるため、人が見ればエラーがあったことが分かりますが、バッチスクリプト的(for コマンドの do 以降で実施される処理的) にはエラーがあったかどうか分かりません。
解決
このような場合、次のように記述すれば for /f で実行したコマンドのエラーを検出することができます。
@echo off for /f "usebackq delims=" %%i in (`dir /b HOGE ^|^| echo *ERROR*`) do if "%%i" == "*ERROR*" ( echo dir コマンドに失敗しました。 ) else ( echo dir コマンドに成功しました。 echo Value: %%~i )
実行結果です。
ファイルが見つかりません dir コマンドに失敗しました。
コマンドのエラーを検出できていることが分かります。
ポイント
下記のようなバッチの記述方法を利用しています。
コマンド1 || コマンド2
"コマンド2" は "コマンド1" が失敗した場合にのみ実行されます。
上述の例で言えば dir コマンドが失敗した場合にのみ、echo *ERROR* が実行され、文字列 *ERROR* が %%i 変数にキャプチャされます。
このため、%%i 変数の内容が *ERROR* か否かによってエラーの有無を判別することができます。
本例ではエラーの有無を判別する文字列を *ERROR* としていますが、全くの任意です。ただ、"コマンド1" の出力として現れないような文字列にしておくことがベターかと思われます。
なお、| (縦線) を for /f コマンドで記述する際は、上述の例のとおり ^ (ハット) でエスケープして ^| と記述する必要があります。
注意点
下記の記述方法で失敗と判断("コマンド2" が実行) される条件ですが、"コマンド1" が 0 以外を返却した場合のもようです。
コマンド1 || コマンド2
次の実験で確認できます。
C:\>cmd /c "exit /b 1" || echo ERROR ERROR C:\>cmd /c "exit /b 0" || echo ERROR C:\>cmd /c "exit /b -1" || echo ERROR ERROR
このため、正常に終了する場合でも 0 以外を返却するコマンドに対しては、今回の手法は利用できません。
例えば robocopy コマンドは、正常に終了する場合でも 0 以外を返却する場合があります。