コマンドの連結
コマンドプロンプトでは、&、&&、|| という記号を使うと、複数のコマンドを 1 行にまとめて実行できます。
「フォルダを作ったら、そこへ移動する」「コピーに失敗したらメッセージを出して終了する」といった処理を、IF 文を使わずに短く書けるため、バッチファイルでもコマンドラインでもよく使われます。
連結演算子の種類
| 記号 | 名前 | 動作 |
|---|---|---|
& | 無条件連結 | 前のコマンドの結果に関係なく、次のコマンドを実行する |
&& | AND(成功時) | 前のコマンドが成功(終了コード 0)した場合のみ実行する |
|| | OR(失敗時) | 前のコマンドが失敗(終了コードが 0 以外)した場合のみ実行する |
コマンドの成功・失敗は、終了コード(ERRORLEVEL)で判定されます。終了コードの詳細はERRORLEVEL の記事を参照してください。
& で順番に実行する
& は、前のコマンドが成功しても失敗しても、続けて次のコマンドを実行します。
コマンド1 & コマンド2
echo %DATE% & echo %TIME%
echo %DATE% のように & の直前にスペースがあると、そのスペースも出力に含まれます。出力を厳密に扱いたい場合は、echo %DATE%& echo %TIME% のようにスペースを詰めて書きます。
&& で成功したときだけ実行する
&& は、前のコマンドが成功した場合にだけ次のコマンドを実行します。「前の処理が終わっていることが前提の処理」をつなぐときに使います。
mkdir work && cd work
mkdir が失敗した場合(権限がない、すでに同名のフォルダやファイルがあるなど)は、cd work は実行されません。なお、すでに work フォルダがある状態でこのコマンドを実行すると mkdir が失敗するため、cd work も実行されない点に注意してください。
copy "report.txt" "D:\backup\report.txt" && del "report.txt"
コピーが失敗したときに元のファイルを消してしまう事故を防げます。
|| で失敗したときだけ実行する
|| は、前のコマンドが失敗した場合にだけ次のコマンドを実行します。エラーメッセージの表示や、処理の中断に便利です。
ping -n 1 192.168.1.1 | find "TTL=" >nul || echo 応答がありません
バッチファイルを途中で終了する
バッチファイルでは、|| exit /b 1 の形でエラー時に処理を打ち切るパターンがよく使われます。
@echo off
cd /d "D:\project" || exit /b 1
copy "config.ini" "config.bak" || exit /b 1
echo 準備が完了しました
exit /b 1 は、バッチファイルを終了コード 1 で終了します。詳しくは
&& と || を組み合わせる
2 つを組み合わせると、成功時と失敗時で処理を分けられます。
tasklist | find "notepad.exe" >nul && echo 起動しています || echo 起動していません
find は、一致する行が見つかれば終了コード 0、見つからなければ 1 を返すため、プロセスやテキストの有無を判定する用途に向いています。それ以外のエラー(ファイルが存在しないなど)では 2 を返しますが、|| は 0 以外をすべて失敗として扱うため、エラー時にも「起動していません」側が実行される点に注意してください。
A && B || C は「A が成功したら B、失敗したら C」と読みたくなりますが、A が成功しても B が失敗すると C も実行されます。
copy "a.txt" "b.txt" && findstr "xyz" "nofile.txt" >nul 2>&1 || echo コピーに失敗しました上記では、コピーが成功しても 2 つ目のコマンド(この例では存在しないファイルを検索する findstr)が失敗すれば「コピーに失敗しました」と表示されてしまいます。厳密な分岐が必要な場合は、
評価の順序
&& と || の優先順位は同じで、左から順に評価されます。条件に合わないためにスキップされたコマンドは、直前の結果を引き継ぎます。
cd /d C:\Windows || echo A && echo B
cd が成功すると echo A はスキップされますが、結果は「成功」のまま引き継がれるため、echo B は実行されます。なお、& は && や || より優先順位が低く、A & B && C は「A を実行し、その後に B && C を実行する」と解釈されます。また、パイプ | やリダイレクトは、これらの演算子よりも先に結び付きます。複雑な組み合わせは意図しない動作になりやすいので、次の丸括弧によるグループ化を使いましょう。
丸括弧でグループ化する
丸括弧 ( ) で複数のコマンドを囲むと、1 つのまとまりとして扱えます。
copy "data.csv" "backup\" >nul || (
echo バックアップに失敗しました
exit /b 1
)
del "data.csv"
A && (成功時) || (失敗時) の形で書くと、成功時のブロックの最後のコマンドが失敗した場合に失敗時のブロックも実行されます。上記のように、失敗時の処理だけを || でグループ化する書き方が安全です。
(echo 日付: %DATE% & echo 時刻: %TIME%) > log.txt
(echo 日付: %DATE% & echo 時刻: %TIME%) > log.txt のようにグループ全体へリダイレクトを付けると、グループ内のすべての標準出力がファイルに保存されます(エラー出力も保存するには 2>&1 を追加します)。リダイレクトについてはリダイレクトの記事を参照してください。
長い連結を複数行に分ける
連結が長くなって読みにくいときは、行末に ^ を置くと改行がエスケープされ、次の行が同じコマンドラインの続きになります。^ の後ろに空白を入れたり、直後に空行を挟んだりしないでください。
mkdir "work" ^
&& cd "work" ^
&& echo 作業フォルダを準備しました
^ の使い方はエスケープの記事で解説しています。
連結するときの注意点
同じ行では設定した変数を参照できない
cmd は 1 行をまとめて解釈してから実行するため、同じ行で設定した変数を %変数名% で参照すると、設定前の値に置き換えられてしまいます。
set MSG=Hello & echo %MSG%
行全体が先に解釈されるため、行を解釈した時点の MSG の値(バッチファイルでは未定義なら空、コマンドラインでは %MSG% のまま)が echo に渡され、Hello とは表示されません。回避するには、バッチファイルで setlocal EnableDelayedExpansion(コマンドラインでは cmd /v:on)を有効にして !MSG! と書くか、コマンドを別の行に分けます。詳しくは
set の値に余分なスペースが入る
set MSG=Hello & echo ... のように書くと、MSG の値は Hello (末尾にスペース付き)になります。& の前のスペースまでが変数の値に含まれてしまうためです。set "MSG=Hello" & echo ... のようにダブルクォートで囲んでください。
IF の後ろに連結を書いた場合
IF の本体の後ろに & や && で続けたコマンドも、IF の条件が真のときだけ実行されます。
if exist "a.txt" echo 見つかりました & echo 処理します
a.txt がなければ、2 つの echo はどちらも実行されません。意図が分かりにくくなるため、複数のコマンドを実行したい場合は丸括弧で囲むことをおすすめします。
robocopy のように成功でも 0 を返さないコマンド
は、ファイルをコピーできた場合に終了コード 1 を返すなど、0 以外でも成功を表すことがあります(8 以上がエラー)。このようなコマンドでは、&& や || では正しく判定できません。
robocopy "src" "dst" /E
if %ERRORLEVEL% GEQ 8 echo コピーに失敗しました
特殊文字としての扱い
& や | は、コマンドプロンプトにとって特殊な文字です。文字として表示したい場合は、echo A ^& B のようにエスケープします。ダブルクォートで囲む方法もありますが、echo "A & B" ではクォートも一緒に出力されます。なお |(
||(OR)、& と && は別の演算子なので混同しないでください。
PowerShell での違い
Windows PowerShell 5.1 では && と || は使用できません(PowerShell 7 以降では使用できます)。この記事の構文は、コマンドプロンプト(cmd.exe)での説明です。
実践例
別ドライブのフォルダへ移動して一覧を表示
cd /d "D:\project" && dir /b
存在しなければ作成する
if not exist "logs" mkdir "logs"
この場合は連結ではなく IF を使うのが適切です。存在確認はファイルの存在確認の記事も参考にしてください。
失敗しても続行したいとき
& を使うと、前のコマンドが失敗しても後続が実行されます。
taskkill /im notepad.exe >nul 2>&1 & timeout /t 3 /nobreak >nul
練習問題
まとめ
| 目的 | 書き方 |
|---|---|
| 結果に関係なく順に実行する | A & B |
| 成功したときだけ次を実行する | A && B |
| 失敗したときだけ次を実行する | A || B |
| 失敗したらバッチファイルを終了 | A || exit /b 1 |
| 複数のコマンドをまとめて扱う | (A & B) && C |
| 長い連結を複数行に分ける | 行末に ^ を置く |
&&と||は直前のコマンドの終了コードで判定されるA && B || Cは if-else の代わりにならない。厳密な分岐はIFを使う- 同じ行で設定した変数は、遅延展開を使わないと
%変数%で参照できない robocopyのように 0 以外でも成功を表すコマンドは、&&や||では正しく判定できない