Jay Bazuzi
Jay Bazuzi

Reputation: 46496

Why does `||` work differently in a batch file if the batch file was run in an interactive CMD?

Suppose I have batch file one.cmd:

@two.cmd && echo success || echo fail

and two.cmd:

@exit /b 1

If I run this at an interactive CMD prompt it behaves one way:

D:\>one.cmd
success

But if I run it under cmd /c it behaves a different way:

D:\>cmd /c one.cmd
fail

Why is this?

Some other cases

PowerShell and Python's subprocess.run both give the same result as cmd /c.

cmd /k gives the same result as running interactively. Which I guess makes sense, given that it's a new interactive shell.

Why this matters

I know how to fix this. Either (or both) of:

  1. any use of || and && should be paired with call.
  2. always exit batch files with cmd.exe /c exit %ERRORLEVEL%.

See more here: Why doesn't Windows batch file `exit` work with `||`?).

My real goal is to write a unit test to ensure that my batch file correctly propagates error on failure, but because the unit test is not using an interactive shell, it doesn't reproduce the problem.

Upvotes: 1

Views: 105

Answers (1)

jeb
jeb

Reputation: 82192

Mofi already mentioned it in his comment: A batch/cmd file have to be called in a batch file.
The cause is, a CALL put a return point to the call stack, but without CALL there is no entry on the stack!
In your case, at first glance, there seems to be no difference, but try to add one more line to one.bat

one.bat

@two.cmd && echo success || echo fail
echo This line will never be reached

Or add a call to a label

one.bat

@two.cmd && echo success || echo fail & call :myLabel
echo This line will never be reached
:myLabel
echo This line will never be reached

Invalid attempt to call a jump target outside a batch file.

The cause for seeing the success or fail messages is the fact, that a line or block will always be cached.
It isn't a return to the code, it's simply the execution of the cache.

Upvotes: 0

Related Questions