バッチからexeを安全に起動するコツ:パス指定・引数・待機
この記事でわかること(結論先出し)
このページでは、バッチファイルからexeを起動するときに迷いやすいstartとcallの違いと、安全に運用するための実践ポイントをまとめます。
単に「起動できる/できない」だけでなく、「次の処理が先に走ってしまう」「引数がうまく渡らない」「環境が変わると動かない」といった実務で起きがちな詰まりも、原因の当たりを付けやすい形で整理します。
先に結論(並列=start/順次=call or start /wait)
結論として、別プロセスで並列に動かしたいならstart、処理の完了を待って次の行へ進めたいならcall(またはstart /wait)を選ぶと整理しやすいです。
迷うポイントは「待つ/待たない」に集約できるので、まずここを決めると、ログの取り方やエラー処理(失敗したら止める/続ける)まで一気に設計しやすくなります。
本記事の前提(bat/cmd、権限、exe位置、カレント)
バッチは実行した場所や権限によって挙動が変わるため、exeのフルパス・作業フォルダ・管理者権限の要否を先に確認しておくとトラブルを減らせます。
特にProgram Files配下の空白パス、相対パス運用時のカレント差、UACによる権限差は“たまにしか起きないのに致命的”になりがちなので、最初に前提を揃えておくのが近道です。
startとcallの違い(まず比較で腹落ち)
startとcallはどちらも「外部コマンドを起動する」点は同じですが、処理の流れや戻り値の扱いが違うため、用途を分けて覚えるのが近道です。
同じ“起動”でも、実務では「この後の処理を止めたいのか」「失敗を検知して中断したいのか」「ユーザーに見える形で起動したいのか」といった要件が混ざります。ここを曖昧にしたまま書くと、たまたま動いていたバッチが環境差で壊れたり、失敗を見逃して後工程で爆発したりします。そこで、まずはstart/callを“比較の型”で整理し、記事後半のパス・引数・ログの話につなげます。
違いは3軸(同期/非同期・戻り値・ウィンドウ)
比べる軸を「待つかどうか」「終了コードをどう扱うか」「ウィンドウやプロセスがどう分かれるか」の3つに固定すると、使い分けがブレません。
- 同期/非同期:起動したexeの完了を待ってから次へ進むか、起動したら次の行へ進むか。
- 戻り値(終了コード):成功/失敗をERRORLEVELで扱える設計にしやすいか。
- ウィンドウ/プロセス:別ウィンドウになるか、プロセスが分かれるか、見た目と裏側の動きがどうなるか。
特に最初の「待つ/待たない」が決まると、後続の設計(ログの取り方、失敗時の分岐、順次/並列の組み立て)が一気に決まります。
比較表(用途別:並列/完了待ち/戻り値で分岐)
次の表は、よくある目的から逆引きできるように整理したものです。 表の“推奨”はあくまで基本方針なので、例外は後半の「待機」「トラブル」「Q&A」で回収します。
| 目的 | 推奨 | 期待する動き | 注意点 |
|---|---|---|---|
| 画面を分けて並列実行したい | start | バッチは先へ進みやすい | タイトル引数の罠がある |
| 完了まで待って次の処理へ進みたい | start /wait | exe終了後に次の行へ | 待機できないケースの切り分けが必要 |
| バッチやサブルーチンを呼び出して戻りたい | call | 呼び出し元へ戻る | 本来はbat/ラベル向け |
| 失敗したら中断したい | start /wait+ERRORLEVEL判定 | 成否で分岐できる | ログがないと原因が見えない |
| 同一ウィンドウでコマンドを続けたい | call(用途次第) | 画面を増やさず次へ進む | exe側の挙動次第で見え方が変わる |
| 起動ディレクトリを明示して安定させたい | start /d(+/wait) | 作業フォルダを固定して起動 | 相対パス運用とセットで考える |
使い分けの決定フロー(迷ったらこれ)
迷ったときは「次の処理を止める必要があるか」を最初に決め、止めるならstart /wait(または制御が必要なbatならcall)、止めないならstartに寄せると判断が早いです。
もう少し具体化すると、次のように考えると迷いが減ります。
- 後続が前工程の成果物を使う(ファイル生成、変換、圧縮、転送など)→ まずは start /wait を基本形にする。
- 部品化したbatや共通処理を呼びたい(入力チェック、ログ初期化、共通後処理など)→ call で“戻ってくる”前提を作る。
- 起動だけしたい(ツールを複数立ち上げる、ユーザーに操作してもらう等)→ start で並列に寄せる。
この判断が固まると、次章以降の「カレント固定」「引用符」「ERRORLEVEL」「ログ化」をどこに入れるべきかも自然に決まります。
exe実行の基本(概念だけ/具体は後半へ寄せる)
exeが起動できない原因の多くは、パスとカレントと権限のどれかに集約できるため、まず概念だけ押さえておくと後半の対策が理解しやすくなります。
特に「手でダブルクリックすると動くのに、バッチだと動かない」「昨日まで動いていたのに今日から動かない」といったケースは、実行する“場所”や“権限”が変わっただけ、ということが少なくありません。ここでの目的は、細かい書き方の前に“ズレが起きるポイント”を把握して、原因の当たりを付けられる状態にすることです。
絶対パス/相対パスの考え方(概念)
絶対パスはどこから実行しても同じ場所を指し、相対パスは「今いるフォルダ」を基準に解釈されるため、運用ではどちらを前提にするかが重要です。
相対パスは書くのが楽で一見シンプルですが、実行環境が変わると参照先が変わるため、運用では事故の温床になりがちです。逆に、絶対パスは冗長に見えても“指す場所がぶれない”ので、安定運用という意味では強い選択肢になります。どちらを使うにしても、記事後半で扱う「作業フォルダ固定(/d や pushd)」とセットで考えると、起動失敗の確率を大きく下げられます。
カレント(作業ディレクトリ)とは何か(概念)
カレントとはプログラムがファイルを探す基準のフォルダで、バッチをダブルクリックしたのかコマンドプロンプトから実行したのかでズレることがあります。
ここがズレると、exe本体は起動しているのに「設定ファイルが見つからない」「出力先が想定と違う」「同梱ファイルが読めない」といった“起動後の失敗”として表に出ることがあります。つまり、症状が「起動できない」ではなく「動きがおかしい」になるのが厄介な点です。カレントの概念を押さえておくと、/dで起動ディレクトリを指定する、あるいはpushdで基準フォルダへ移動してから実行する、といった対策の意味が腹落ちします。
管理者権限が絡むと何が起きるか(概念)
管理者権限が必要なexeを通常権限で起動すると失敗したり別の場所に書き込めなかったりするため、UACの影響を切り分けられるようにしておきます。
たとえばシステム配下への書き込み、サービス操作、レジストリ変更などは権限不足で失敗しやすく、エラーが出ずに“実は反映されていない”ケースもあります。また、同じユーザーでも「管理者として実行」かどうかで権限が変わるため、手動実行とバッチ実行で結果が違うことが起きます。権限が疑わしいときは、ログやエラー出力に“アクセス拒否”系の情報がないかを確認し、必要なら実行方法(管理者実行、実行場所の変更)を見直す、という切り分けができるようにしておくと安全です。
startコマンドの使い方(start固有の書き方に集中)
startは別プロセス起動に強い一方で、書き方を誤ると「意図と違う対象が開く」「引数がずれる」などの事故が起きやすいコマンドです。
逆に言えば、最低限の定石(引用符、タイトル、待機、作業フォルダ)を押さえておけば、並列実行やGUIアプリの起動を安定させやすく、バッチの“つなぎ役”として非常に便利になります。また、見た目(ウィンドウ挙動)と裏側(プロセスの分かれ方)が一致しないケースもあるため、挙動を理解した上で使うことが重要です。
基本構文+最重要の落とし穴(タイトル引数問題)
startは先頭のダブルクォートが「ウィンドウタイトル」と解釈されることがあるため、空タイトルを明示する書き方を癖にすると安全です。
特にexeのパスに空白がある環境(例:Program Files配下)では、この罠に引っかかりやすく、「起動できない」「別のフォルダが開く」「引数が消える」といった症状として現れます。基本形は「空タイトル → 実行ファイル(必要なら引用符)→ 引数」の順に並べることです。引数にも空白が含まれる場合は、引数単位で引用符を付け、exeパスと混在させないようにします。
ウィンドウ挙動(新規/同一)と用途
startは新しいウィンドウを開いて実行することが多く、ユーザーに見せたい処理や並列起動に向いています。
たとえば複数ツールを同時に立ち上げる場合、startを使えばバッチ側は待たずに次の行へ進むため、起動処理を一括で実行できます。一方で、ウィンドウが増えること自体が問題になる場面(裏で静かに動かしたい、画面を増やしたくない)では、/bオプションや設計の見直しを検討する必要があります。
よく使うオプション(/wait 等)早見表
使用頻度の高いオプションを押さえておくと、実務でのトラブルを大幅に減らせます。
特に/waitは「次の行を止めたい」という要件に直結し、/dは「カレントが違って動かない」問題を回避するために重要です。まずはこの2つを確実に使いこなせるようにしましょう。
| オプション | 効果 | 使いどころ |
|---|---|---|
| /wait | 起動したプロセスの終了まで待つ | 後続処理を順番に実行したい場合 |
| /d | 作業フォルダを指定して起動する | 相対パス依存の不具合を防ぎたい場合 |
| /min | 最小化して起動する | 画面を邪魔したくない場合 |
| /b | 新しいウィンドウを作らず実行する | 同一ウィンドウ内で実行したい場合 |
startは便利ですが、引用符とオプションの理解が浅いと“たまたま動いている状態”になりがちです。基本形をテンプレート化し、毎回同じ型で書くことが安定運用への近道です。
callコマンドの使い方(callの意味と制御フロー)
callは「呼び出して戻る」ための制御コマンドとして覚えると、startと混同しにくくなります。
startが“新しい処理を起動する”寄りの発想だとすると、callは“処理をつなぐ(流れを作る)”ための発想に近いです。バッチを長く運用するほど、処理を部品化して再利用したくなるので、callの役割を押さえておくと保守性が上がります。
callの基本(戻って次の行が動く)
callは呼び出し先の処理が終わったら呼び出し元に戻り、続きの行を実行できる仕組みです。
つまり「ここで一度別の処理へ移動するが、終わったら必ず帰ってくる」という前提でフローを組み立てられます。単純な順次実行ならそのまま書けばよいのですが、同じ処理を何度も使う、途中で共通の後処理を挟む、といったケースではcallを使うと重複を減らせます。
callの主戦場(別bat/サブルーチン)
callは別のbatを部品化して呼ぶときや、ラベルを使ったサブルーチンを呼び出すときに真価を発揮します。
たとえば「ログ初期化」「入力チェック」「共通のエラー処理」といった処理をサブルーチン化しておけば、どの工程でも同じルールで動かせます。さらに、部品側(呼び出される側)でexit /bとERRORLEVELをきちんと扱えば、呼び出し元は成功/失敗を受け取って分岐でき、全体の挙動が読みやすくなります。
exeにcallする場合の注意(戻り値・待機の誤解防止)
callでexeを起動できても、startと同じ感覚でウィンドウや引数を扱えるとは限らないため、戻り値と待機の挙動を前提にして設計します。
特に「call=必ず完了まで待つ」と思い込むと、exeの種類や起動方法によって期待とズレることがあるので注意が必要です(ランチャー型のexeや、別プロセスへ処理を委譲するタイプなど)。また、引数の引用符やカレントの影響はcallでも同様に受けるため、起動前チェック(存在確認)と起動後チェック(ERRORLEVEL判定)、そしてログ出力をセットで組み込むと、startを使う場合と同じように安定した運用につながります。
待機(同期)を意図通りにする(“止めたい”検索意図に直撃)
バッチからexeを起動するときの最頻出の悩みは「次の行が先に動いてしまう」ことで、待機の設計を一段目に置くと全体が安定します。
特に後続処理が「生成されたファイルを読む」「出力先フォルダを圧縮する」「結果を別サーバーへ転送する」といった“前の処理が終わっている前提”で動く場合、待機が抜けているだけでデータ欠損や中途半端な成果物を作る原因になります。逆に言うと、待機の方針さえ決まれば、start/callの使い分けやエラー処理も一本の線でつながり、全体の設計がシンプルになります。
確実に完了待ちしたい:start /wait の基本
完了待ちが必要ならstart /waitを基本形として扱い、後続の処理が先走らない形にします。
ここで意識したいのは「待つ対象が本当に“本体”か」という点で、ランチャー型アプリやアップデータのように“別プロセスを起動して自分は終了する”作りだと、/waitしても体感では待てていないように見えることがあります。その場合は、起動するexeを本体側に変える、または成果物(ログや出力ファイル)の生成を待つなど、待機条件を見直す発想が必要です。
複数exeを順番に実行するパターン
順番に実行したいときは、1つ目を待ってから2つ目を起動する流れにし、途中で失敗したら止める分岐もセットで用意します。
ポイントは「どこで失敗したか」を後から追えるように、工程ごとに開始・終了のメッセージを出すことです。例えばSTEP1が終わったことがログに残っていれば、次に疑うべきはSTEP2の起動や引数の問題だと分かります。順次実行は単純に見えますが、運用では“途中で止まったときの復旧”が重要になるため、分岐とログを最初から組み込んでおくと安全です。
固まらせない工夫(タイムアウト/ポーリング発想)
待機は便利ですが永遠に待つ設計は運用事故につながるため、時間制限や状態確認の仕組みを想定しておくと安全です。
たとえば外部ツールがハングしたり、ネットワーク越しの処理が止まったりすると、バッチ全体が“終わらない”状態になり、次の定期実行や運用手順に影響が出ます。そこで「一定時間で諦めて失敗扱いにする」「ログや出力ファイルの更新を監視して進捗を判断する」など、待機を“制御可能な待機”に寄せておくと安定します。最初から完璧な仕組みを作る必要はありませんが、少なくとも“止まったときに止まったと分かる”設計にしておくと、現場での復旧が格段に楽になります。
安全に起動するコツ1:パス指定(空白・日本語)を壊さない
起動失敗の多くは「パスの空白」「引用符の位置」「実行場所のズレ」で説明できるため、まずパスの扱いを固めるのが効果的です。
特にWindowsでは Program Files のように空白を含む場所にインストールされていることが多く、引用符が1つずれるだけで「exeではなくフォルダを開く」「引数がパスの一部として解釈される」といった誤動作につながります。ここでは“起動できない”を減らすために、パスの書き方と実行場所の固定をセットで考えます。
ダブルクォートの基本(どこを括る?)
空白を含むパスは必ずダブルクォートで括り、実行ファイル本体と引数の境界が崩れないようにします。
ポイントは「括る対象を混ぜない」ことで、exeのパスはexeのパスだけ、空白を含む引数はその引数だけを括る、という意識で書くと崩れにくくなります。また、パスに日本語が含まれる環境では、バッチの文字コードや表示とのズレで見落としが起きやすいので、ログにそのまま出して“実際に渡している文字列”を確認できるようにしておくと安全です。
相対パス運用なら基準固定(pushd/popd 等)
相対パスを使うなら実行開始時に基準フォルダへ移動し、処理後に元へ戻る形にすると、環境差による失敗が減ります。
ダブルクリック実行とコマンドプロンプト実行でカレントが変わると、相対パスが別の場所を指してしまい「ファイルが無い」扱いになりがちです。そこで、最初に基準フォルダへ移動してから処理を進める(終了時に元へ戻す)流れをテンプレ化すると、実行場所のブレを吸収できます。ネットワークドライブやUNCパスを扱う場合も、作業フォルダを明示しておくと“権限や接続状態”の切り分けがやりやすくなります。
存在チェック(if exist)+親切なエラー表示
実行前にファイルの存在を確認しておけば、起動できない原因が「そもそも無い」「場所が違う」といった初歩に戻ってしまうのを防げます。
ここで重要なのは、単に止めるだけでなく「どのパスを探したのか」「カレントはどこだったのか」をメッセージに含めることです。そうすると、あとでログを見返したときに“パスの組み立てが間違っていたのか/実行場所がズレていたのか”が一発で分かり、再現が難しい環境差のトラブルでも復旧が速くなります。
安全に起動するコツ2:引数の渡し方(共通ルール+罠)
exeへ渡す引数は、空白や記号が混ざると分割のされ方が変わるため、引用符のルールを理解してログで確認できるようにします。
特に「パスは合っているのに起動設定だけが反映されない」「オプションが無視される」といった現象は、引数の区切りが崩れて別の意味に解釈されていることが原因になりやすいです。まずは“どの単位で引数として渡したいか”を先に決め、その単位ごとに引用符を付ける、という考え方で整理すると事故が減ります。
引用符ルール(空白/記号を含む引数)
引数に空白が入る場合はその引数だけを括り、全体を雑に括って解釈を崩さないようにします。
さらに、引数の中に引用符が必要になるケース(パスを引数として渡す、値が空白を含む設定を渡す等)では、どこからどこまでが1つの値かが伝わるように“最小限の範囲”で括るのが基本です。また、記号を含む引数は見た目どおりに扱われないことがあるため、まずは引用符で値を固めてから、必要に応じてエスケープや別の受け渡し方法(設定ファイル・環境変数など)を検討します。
ログ出力で見える化(echo で組み立て確認)
起動直前に実行するコマンド文字列をechoで表示すると、思っている引数と実際に渡っている引数のズレに気づきやすくなります。
ポイントは「実行前に出す」ことと「出した内容を残す」ことで、手元では再現しないトラブルでも、ログが残っていれば後から同じ入力を再現できます。加えて、引数が長い場合は、どの値がどのオプションに対応しているかを読み返せるように、見やすい形で出力する(区切りを入れる、開始メッセージを出すなど)と、原因切り分けが一段早くなります。
環境変数の注意(展開タイミングの罠)
環境変数を引数に使う場合は、値に空白が含まれる可能性や展開タイミングによって文字列が変わる可能性も考慮します。
たとえば同じ変数名でも、実行環境(ダブルクリック/タスク/別バッチ呼び出し)で中身が違うことがあり、引数の一部が欠けたり余計な文字が混ざったりして不具合につながります。さらに、変数の中身に空白や記号が含まれるなら、その変数を使う“側”で引用符を付ける前提にしておくと安全です。最後に、環境変数が想定どおりに展開されているかは、起動直前のログ出力で確認できるようにしておくと、現場での復旧が速くなります。
失敗を検知する:戻り値(ERRORLEVEL)とエラー処理
起動できたかどうかを人の目で判断する運用は破綻しやすいので、終了コードとログで機械的に検知できる形にします。
ここで大事なのは「失敗を見逃さない」ことだけでなく、「失敗したときに原因を追える材料を残す」ことです。終了コード(ERRORLEVEL)は分岐の起点になり、ログは原因究明の根拠になります。どちらか片方だけだと運用が不安定になりやすいので、セットで設計するのがコツです。
ERRORLEVELの基本+判定の定石
終了コードは0が成功でそれ以外が失敗という設計が一般的ですが、実際の意味はexe側の仕様に依存するため、判定のしかたは固定しておきます。
具体的には「実行直後に必ずERRORLEVELを読む」「成功・失敗で必ず分岐する」「失敗側では原因特定に必要な情報(対象パス、引数、カレント)を出す」をルール化すると安定します。また、比較演算は if errorlevel 1 のように“以上判定”になる点も踏まえ、条件の書き方をチーム内で統一しておくとミスが減ります。
標準出力/標準エラーのリダイレクト(ログ化)早見表
ログを残すと「起動はしたが途中で失敗した」「設定ファイルが見つからない」といった情報が取れるため、運用の再現性が上がります。
ポイントは標準出力(通常ログ)と標準エラー(エラーログ)を分けて考えることと、必要に応じて両方をまとめて保存することです。特に“何も起きない”系のトラブルは標準エラーにしかヒントが出ないこともあるので、最初から両方を取る設計にしておくと切り分けが早くなります。
| 目的 | 書き方のイメージ | 意味 |
|---|---|---|
| 出力をファイルへ | > log.txt | 標準出力を保存する |
| エラーをファイルへ | 2> err.txt | 標準エラーを保存する |
| 両方まとめて保存 | > all.txt 2>&1 | まとめて1つにする |
| 追記で残す(上書きしない) | >> log.txt | 既存ログの末尾に追記する |
exit /b の使いどころ(呼び出し元へ正しく返す)
バッチを部品として使う場合は、失敗したときにexit /bで適切なコードを返すと、上位の処理が安全に止められます。
ここでのコツは「失敗を握りつぶさない」ことです。たとえば途中でエラーが出たのに0で終了してしまうと、呼び出し元は成功と誤認して次の処理を進めてしまいます。逆に、失敗時に非0を返す運用を徹底しておけば、上位のバッチやジョブスケジューラ側で確実に検知でき、再実行やアラートにつなげやすくなります。
実用テンプレ(コピペで使える)
ここでは、実務でそのまま使える形のテンプレを用意し、目的ごとに差し替えポイントが分かるようにします。
まずは「起動対象」「作業フォルダ」「ログの出力先」の3点を変数として先頭に集めておくと、案件ごとに差し替える場所が固定できて保守が楽になります。さらに、実行前チェック(存在確認)と、実行後チェック(戻り値判定)をセットで考えると、テンプレを“安全運用用の部品”として使い回せます。
並列起動テンプレ(start)
並列起動は便利ですがログや失敗検知が薄くなりがちなので、何を起動したかが追える形にしておきます。
並列にするほど「どれが失敗したのか」が見えなくなるため、最低限のメタ情報(開始時刻・対象・引数)を残す発想が重要です。
- 起動対象のパスは必ず引用符で括る(空白パス対策)。
- 起動前にechoで対象を出す(パスと引数を見える化)。
- 必要ならstartのタイトル引数を空で明示する。
- 作業フォルダが重要なら固定する(/d または事前移動の発想)。
完了待ちテンプレ(start /wait)
完了待ちテンプレは、後続処理の前提を作るための基本形として用意しておくと、毎回の作り直しが減ります。
「待つ→判定する→次へ進む」をワンセットにし、成功時と失敗時で必ず分岐する形にしておくと、失敗を見逃しにくくなります。
- start /waitで完了を待つ。
- 直後にERRORLEVELで分岐する。
- 成功時と失敗時でログの出し方を変える。
失敗時に中断するテンプレ(ERRORLEVEL分岐+ログ)
失敗時に続行してしまうのが一番危険なので、判定して止める形をテンプレ化しておくと安全です。
失敗したときに「どこで」「何が」起きたかを残せるようにしておけば、原因切り分けと再発防止が格段に楽になります。
- 失敗したらメッセージを出してexit /bで返す。
- ログファイルの場所を固定する。
- 起動対象が存在しない場合も同じルートで止める。
よくあるトラブルと対処(検索で来る詰まりを最短解決)
トラブルは再現しにくいことが多いので、「いま何が起きているか」を観測できる形にしてから、現象→原因候補→対処の順で潰していくのが近道です。
特にバッチはダブルクリック実行だと画面が一瞬で閉じてしまい、情報が残らないまま詰まりがちなので、まずはログを出して“証拠”を残すところから始めると解決が速くなります。
何も起きない/一瞬で閉じる(ログで確認する順序)
まずは「起動しようとしているパスが正しいか(if existで確認)」、次に「カレントが想定どおりか(pushd/popdやecho %cd%で確認)」、最後に「ログにエラーが出ていないか(標準エラーも含めて保存)」の順で確認すると無駄が少ないです。
加えて、起動直前に実行コマンドをechoで表示しておくと、引用符や引数の崩れにも早めに気づけます。GUIアプリで画面が閉じてしまう場合は、一時的に pause を入れてメッセージを読めるようにするのも有効です。
別のファイルが開く/タイトル扱いになる(startの罠)
startで先頭に引用符を置くとタイトル扱いになり得るため、空タイトルを明示してから実行ファイルを指定すると事故を避けられます。
たとえば空白パスのexeを起動するなら、start "" "C:\Path With Space\app.exe" の形を基本として覚えると安定します。また、拡張子の関連付けによっては、exeではなく“既定のアプリで開く”動きになることもあるので、対象が本当にexeか、パスがショートカット(.lnk)になっていないかもチェックすると切り分けが進みます。
パスは合っているのに起動できない(権限/依存/実行場所)
権限が足りない、必要なDLLや設定ファイルが見つからない、ネットワークドライブの権限が違うなどの環境要因も疑うと切り分けが進みます。
特に「手動では起動できるのにバッチだと失敗する」場合は、カレントの違いで設定ファイルを見失っているケースが多いので、/dで作業フォルダを固定する、または起動前にpushdで移動してから実行するのが有効です。管理者権限が必要な処理なら、同じユーザーでも実行方法によって権限が変わることがあるため、イベントログやエラーログに“アクセス拒否”が出ていないかも併せて確認します。
よくある質問(Q&A:例外ケース寄せ)
最後に、実務でよく遭遇する例外パターンを少しだけ詳しく回収して、同じところで詰まらないようにします。
ここに書いてある内容は「現象→原因→対処」の順で読めるようにしてあるので、困ったときは該当箇所だけ拾い読みしてもOKです。
startで空白パスが動かないのはなぜ?(タイトル引数問題)
startは最初の引用符をタイトル(ウィンドウ名)と解釈する場合があるため、空タイトルを入れてから実行ファイルの引用符を置くと挙動が安定します。
たとえば start "" "C:\\Program Files\\App\\app.exe" のように、先に空文字を置くのが定石です。また、引数にも空白が入るなら「exeのパス」と「引数」を別々に引用符で括り、どこまでがパスでどこからが引数かを崩さないようにします。
start /waitでも待てないケースはある?
起動したexeが別プロセスを生成してすぐ終わる設計だと、/waitが待つ対象が「最初に起動した親プロセス」だけになり、体感としては待てていないように見えることがあります。
例えばランチャーが本体を起動して自分は終了するタイプのアプリだと、この現象が起きやすいです。対処としては、どのプロセスが本体かをタスクマネージャー等で確認し、待つべき対象を変える(起動するexeを本体側にする/本体が作るログやファイルの生成を待つ設計にする)など、待機条件を「プロセス終了」以外に置くことも検討します。
終了コードが取れない/常に0になる時の確認点
exe側が終了コードを返していない(常に0を返す)可能性があるため、ERRORLEVELだけで判定できる前提を疑い、ログの内容や出力ファイルの有無と合わせて確認します。
特にGUIアプリは終了コードが有用でないこともあるので、エラー時に特定のメッセージを出すか、エラーログを出力する設定がないかを先に探すと早いです。必要なら「ログに特定文字列があるか」「出力ファイルが更新されたか」など別の成功判定方法も用意し、運用として“判定できない=失敗扱い”に寄せておくと安全です。
まとめ
startとcallは「待つかどうか」と「戻り値の扱い」と「プロセスの分かれ方」で整理すると迷いが減り、パス・引数・待機・エラー処理の4点を押さえるとバッチ運用が安定します。
特にstartはタイトル引数の罠と引用符の位置で誤動作しやすいので、空タイトルを明示し、必要に応じて/waitや/dで挙動を固定するのがコツです。さらにif existで起動前チェックを入れ、実行結果はERRORLEVELとログ(標準出力/標準エラー)で機械的に判定できる形にすると、原因切り分けと再発防止がぐっと楽になります。