7

(I am using Win10 20H2)
I know if you have command A && command B, then command B only executes if command A was "completed successfully", but how exactly is it decided whether command A was successful or not?

  • My first thought was that it must be based on errorlevel's, but that can't be it as the following shows if you press enter without entering an input, then, as expected, you will not see a "success" message and the errorlevel is changed to 1:
    @echo off
    :loop
    set /p u_p= && echo success
    echo current errorlevel %errorlevel%
    goto loop
    
    However, if you subsequently enter valid inputs, you get a success message despite the errorlevel remaining at 1, so what is triggering the && to give the success message?

  • It has been suggested delayed expansion might be needed, as without it the code is false reporting the current errorlevel, however I've tried that, along with replacing the line referencing the errorlevel, but I still get the outputs to indicate success despite the errorlevel not being 0 for all subsequent inputs after entering an empty input:
    if errorlevel 1 (echo current errorlevel geq 1) else (echo current errorlevel leq 0)
    

I am reasonably certain the explanation is not && is being triggered by a 0 errorlevel, but that the code is causing a false reporting of the errorlevel?

JW0914
  • 7,865
TechHorse
  • 347

2 Answers2

1

My first thought was that it must be based on errorlevels.

It is, but you are missing enabledelayedexpansion.

This is required because there is effectively a loop in your script and without enabledelayedexpansion the errorlevel variable is set the first time through and then doesn't change.

Using setlocal enabledelayedexpansion will give the behaviour you are expecting:

@echo off
setlocal enabledelayedexpansion
:loop
set /p u_p= && echo success
echo current errorlevel %errorlevel%
goto loop
endlocal

EnableDelayedExpansion

Setting EnabledDelayedExpansion will cause each variable to be expanded at execution time rather than at parse time.

Source Setlocal - Local variables - Windows CMD - SS64.com


Further Reading

DavidPostill
  • 156,873
  • 2
    That doesn't work for me, even if I replace the %s with!s? – TechHorse Dec 20 '21 at 23:38
  • @TechHorse Works for me. I have tested it. – DavidPostill Dec 21 '21 at 01:49
  • I am using Win 10 20H2. I do not think it sets an errorlevel for valid set/p inputs. Perhaps you're version is different. – TechHorse Dec 21 '21 at 12:42
  • I have added anedit to include steps I have taken to ensure that the explanation is not just the code false reporting the errorlevel. – TechHorse Dec 21 '21 at 13:03
  • According to the claims at https://stackoverflow.com/questions/34987885/what-are-the-errorlevel-values-set-by-internal-cmd-exe-commands the errorlevel, once set to 1 by not entering an actual value, will never be reset to 0. See Table 3 re the set /p command. – kreemoweet Dec 23 '21 at 23:09
  • @kreemoweet That table does not agree with my test program. – DavidPostill Dec 23 '21 at 23:45
0

How does && work in a Batch File?

  • && will execute the next command when the previous command returns 0
  • || will execute the next command when the previous command returns non 0

Almost all applications and utilities will set an Exit Code when they complete/terminate:

You won't get return 0 useful with the set /p command, it makes no effect accurate waiting for the && (return 0) to execute the next command, especially if it's on the same line, regardless of whether setlocal is enabled or not

  • Success is defined as returning an %ERRORLEVEL% = 0; care must be taken in using this syntax to read and SET variables, as by default variables are expanded one line at a time
  • It is not accurate to execute a command after defining a variable without checking if it has been defined or not, nor if the value is in the desired scope, layout, length, etc.

Whatever the input, whether it was given or not, it ends if Enter was pressed, in which case you have errorlevel 0, if Ctrl+C was used, it would end that you have errorlevel 1 in this way, outside of this scenario, no has a lot of use for && and/or ||.


  • For something more precise, I suggest checking if any values ​​are assigned / assumed in your variable:
    if defined u_p (do) else (do instead)
    

    rem or ::

    if not "" == "%u_p%" (do) else (do instead)


  • Porting to your code, I suggest something simple:
    @echo off
    

    :loop set "u_p="

    set /p u_p= || goto loop if "%u_p%" == "" goto :loop

    rem :: do next command here ...


Additional Resources:

JW0914
  • 7,865
Io-oI
  • 8,193