CMD の継続演算子

CMD にはコマンドの終了コードを使用して次のコマンドを実行するかどうかを決定する継続演算子があります。

command1 & command2

と記載すると、command1 の終了後に command2 を実行します。

command1 && command2

と記載すると、command1 の終了コードが 0 の場合のみ command2 を実行し、

command1 || command2

と記載すると、command1 の終了コードが 0 以外の場合のみ command2 を実行します。

コマンドの終了コードと ERRORLEVEL は異なります。上記の && と || は ERRORLEVEL ではなく終了コードを見て次のコマンドの実行判定をすることに注意が必要です。特に注意が必要なのはバッチファイルの呼び出し処理です。バッチファイルの呼び出しはファイル名を記載するか CALL コマンドで行うことができますが、前に書いているイメージのように EXIT コマンドが設定するのは ERRORLEVEL であって終了コードではないことに注意が必要です。

終了コードは Win32 のプロセスが終了するときに設定するものであって、CMD.exe という1つのプロセスの中で(外部のバッチファイルの呼び出しを含めて)バッチ処理を進めていく最中に参照されている状態ではないということです。もちろん、CMD の内部コマンドは Win32 のプロセスの終了コードをシミュレートしてくれるので、

REM 存在しないドライブを順番に表示しようとする
dir P: || dir Q: || dir R: || dir S:
 ドライブ R のボリューム ラベルは RAM-DRIVE です
 ボリューム シリアル番号は 1234-5678 です

などとすれば dir コマンドはきちんと終了コードを返しているかのように動き、P: Q: が存在しない場合に dir R: が実行されます。
ここで注意が必要なのは CALL コマンドを含めたバッチファイルの呼び出しの場合です。CALL コマンドは「対象のバッチファイルまたはラベルが呼び出せた場合に成功、呼び出せない場合に失敗」となっています。つまり、

file.bat || echo file.bat がみつかりませんでした。

という処理は file.bat が存在すれば file.bat を実行し、file.bat が存在しなければメッセージを出力するという意味になります。*1 呼び出されたバッチファイル file.bat の中身から呼び出し元に終了状態を伝える方法は、前半に書いているように EXIT コマンドを使用して ERRORLEVEL を設定することです*2が、&& や || は終了コードを判定するため file.bat がどのような結果になったかに関係なく、バッチ処理を呼び出せたかどうかだけが判断の基準になります。
ERRORLEVEL を使用してエラー判定をしようとすると

file.bat && IF ERRORLEVEL 1 ECHO 実行に失敗しました

という感じになりますが、CALL コマンドが失敗した場合、IF 〜 は実行されず「実行に失敗しました」は表示されないことになります。ちょっと困りますよね。場合分けが必要ではないならば

file.bat & IF ERRORLEVEL 1 ECHO file.bat が見つからないか、file.bat が失敗しました

といったかんじで、& にするとファイルがない場合と呼び出し先でエラーになった場合の両方にメッセージを出力できます。呼び出しが成功してエラーが発生しなかった場合のみ実行する場合には、

file.bat && IF NOT ERRORLEVEL 1 ECHO 成功しました

と、&& と NOT を使用する感じになります。ちなみに、CALL コマンドは ERRORLEVEL にエラー明細を設定してくれるので、ファイル名を直接書くよりも細かいエラー判定ができます。

*1:再帰が深すぎて file.bat を実行できない場合にもメッセージが出力されると思いますが…

*2:もちろん、環境変数等も手段としてあります