Page 1 of 1

On "color" command and errorlevel

Posted: 07 Dec 2020 04:59
by Meerkat
Today I revisited the amazing %mm% macro, and I had a comment there that it errors out when the Batch file is opened by clicking (unlike when opened in CMD). Upon debugging, I realized that the "bug" is on the COLOR command which is used to set the errorlevel. Example:

Code: Select all

@echo off
color 00
echo(%errorlevel%
color
echo(%errorlevel%
pause
When the above code is opened in CMD, the output is "1" then "0", which is the right output. On the other hand, when same is opened by double-clicking, the output is both "1", which (I think) means that the color command without parameters didn't "change" the color, hence didn't set the errorlevel to 0. Note that this happens regardless of whether the script is .bat or .cmd. Why this happens? :cry:

Maybe double-clicking is not the right way to execute Batch scripts.

Is there a fix that still uses color command? If no, then what are some alternatives to setting errorlevel? Is

Code: Select all

set "errorlevel=0"
a "good" one?

Tested on a Windows 10 64-bit. Maybe I will also make another test on a different PC.

Thanks,

Meerkat

Re: On "color" command and errorlevel

Posted: 07 Dec 2020 05:14
by T3RRY
Errorlevel can be forced using call and parentheses.
Errorlevel 1

Code: Select all

(Call)
Errorlevel 0

Code: Select all

(Call )
However more versatility can be achieved be defining a seperate variable for the error return as used in my findstr colorprint macro

Code: Select all

@Echo off
PUSHD "%TEMP%"
rem /* Macro Definitions */
(Set  \n=^^^
%= macro newline Do not modify =%
)
(Set LF=^


%= linefeed. Do not modify =%)
 If "!![" == "[" (
  Echo/%%COL%% macro must be defined prior to delayed expansion being enabled
  Goto :end
 )
(Set COMMENT=rem {i} ^^^
%= macro Comment line. Do not modify =%
)
 For /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (set "DEL=%%a")
rem /* %hCol% - Alternate color macro; escaped for use in COL macro. No error checking. Usage: (%hCol:?=HEXVALUE%Output String) */
 Set "hCol=For %%o in (1 2)Do if %%o==2 (^<nul set /p ".=%DEL%" ^> "!os!" ^& findstr /v /a:? /R "^$" "!os!" nul ^& del "!os!" ^> nul 2^>^&1 )Else Set os="
rem /* %TB%   - used with substitution within COL macro to format help output; not fit for general use, */
 Set "TB=^&^< nul Set /P "=.%DEL%!TAB!"^&"
rem /* %COL%  - main color output macro. Usage: (%COL%{[a-f0-9][a-f0-9]}{String to Print}) */
rem /* IMPORTANT: maximimum single line output length of 227 characters for all macro Concatenations on same line. may vary depending on console properties. */
 Set COL=Set "_e=0"^&Set "Oline="^& For %%l in (1 2)Do if %%l==2 (%\n%
 %COMMENT:{i}= Reset vars Oline and _e prior to redefining Oline and commencing macro main body \n%
  If not "!Oline!" == "" (%\n%
   Set "_Str="%\n%
 %COMMENT:{i}= Capture {Arg 1 HEX} {Arg2 output String} \n%
   For /F "tokens=1,2 Delims={}" %%G in ("!oline!")Do (%\n%
    Set "Hex=%%G"%\n%
    Set "_Str=%%~H"%\n%
   )%\n%
 %COMMENT:{i}= test HEX sting is within valid range, flag true or false using _e and Str vars to control error handling. \n%
 %COMMENT:{i}= remove this comment line and the below line for faster performace. Incorrect hex values will print console default colors \n%
   Echo/!Hex!^|findstr /RX "[0-9a-fA-F][0-9a-fA-F]" ^> nul ^|^| (Echo/^&(%hCol:?=04%Invalid - )%TB%(%hCol:?=06%Bad Hex value.)%TB%(%hCol:?=01%%%COL%%{!Hex!}{!_Str!})%TB:TAB=LF%(%hCol:?=02%!Usage!)^&Set "_Str="^&Set "_e=1")%\n%
   If not "!_Str!" == "" (%\n%
 %COMMENT:{i}= Create file with the name of the output string to print in Color using findstr if all Args valid \n%
    ^<nul set /p ".=%DEL%" ^> "!_Str!"%\n%
    findstr /v /a:!Hex! /R "^$" "!_Str!" nul 2^> nul %\n%
 %COMMENT:{i}= delete the created file. \n%
    del "!_Str!" ^> nul 2^>^&1 %\n%
   )Else If not !_e! EQU 1 (%\n%
 %COMMENT:{i}= No Arg 2 Error handling  \n%
    Set "_e=2"^&Echo/^&(%hCol:?=04%Invalid -)%TB%(%hCol:?=06%Arg 2 absent.)%TB%(%hCol:?=01%%%COL%%!Oline!)%TB:TAB=LF%(%hCol:?=04%Input is required for output string.)%TB:TAB=LF%(%hCol:?=02%!Usage!)%\n%
   )%\n%
  )Else (%\n%
 %COMMENT:{i}= No args Error Handling \n%
   Set "_e=3"^&Echo/^&(%hCol:?=04%Invalid -)%TB%(%hCol:?=06%No Args)%TB:TAB=!TAB!!TAB!%(%hCol:?=01%%%COL%%!Oline!)%TB:TAB=LF%(%hCol:?=02%!Usage!)%\n%
  )%\n%
 )Else Set Oline=
 Set "usage=%%COL%%{[a-f0-9][a-f0-9]}{String to Print}"
 For /F eol^=^%LF%%LF%^ delims^= %%A in ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x09"') do Set "TAB=%%A"
rem /* removes escaping from macros to enable use outside of COL macro */
 Set "hCol=%hCol:^=%"
 Set "TB=%TB:^=%"
 Setlocal EnableDelayedExpansion
 rem /* usage examples. NOTE: expanded macro concatenations should be kept to a minimum as mulitple expansions
 rem    may exceed the line length limit of the parser. */
 (%COL%{02}{"green on black,"})
 (%COL%{10}{"black on blue"})
 Echo/
 (%COL%{04}{"red on black"})
 (%COL%{34}{" red on blue"})
 (%COL%{40}{"black on red"})
 Echo/& %COL%{03}{Demonstration of error handling-}
rem /* error handling *
 Echo/%TB:TAB=!LF! % %hCol:?=20%Example 1 - No args
%COL%
 Echo/%TB:TAB=!LF! % %hCol:?=20%Example 2 - Missing 2nd Arg
%COL%{ff}
 Echo/%TB:TAB=!LF! % %hCol:?=20%Example 3 - Invalid hex value for 1st Arg
%COL%{HF}{string}
 Echo/%TB:TAB=!LF! % %hCol:?=0d%Done
:end
 POPD
Goto :Eof

Re: On "color" command and errorlevel

Posted: 07 Dec 2020 07:27
by Meerkat
T3RRY wrote:
07 Dec 2020 05:14
Errorlevel can be forced using call and parentheses.
Errorlevel 1

Code: Select all

(Call)
Errorlevel 0

Code: Select all

(Call )
I just tested this, and I just found out that (call ) (with space) is a very tiny bit slower than (call), but the color command without parameter is obviously slow, while color 00 is fast. This makes the call method the even better method because of speed. Thanks!
T3RRY wrote:
07 Dec 2020 05:14

However more versatility can be achieved be defining a seperate variable for the error return as used in my findstr colorprint macro

...
O That's nice. Hmm... I̶ ̶p̶r̶e̶f̶e̶r̶ ̶h̶a̶v̶i̶n̶g̶ ̶b̶o̶t̶h̶ ̶t̶h̶e̶ ̶e̶r̶r̶o̶r̶l̶e̶v̶e̶l̶ ̶a̶n̶d̶ ̶t̶h̶e̶ ̶s̶e̶p̶a̶r̶a̶t̶e̶ ̶v̶a̶r̶i̶a̶b̶l̶e̶ ̶f̶o̶r̶ ̶e̶r̶r̶o̶r̶ ̶i̶n̶f̶o (see my reply below), but I am not the creator of %mm% and everyone has their own style.
BTW, the popd doesn't seem to work when your code is opened in CMD.

Meerkat

Re: On "color" command and errorlevel

Posted: 07 Dec 2020 08:03
by aGerman
A very general approach to change the errorlevel is to use cmd /c exit n with n the errorlevel value you want to set. However, I suspect this is slow because it doesn't just invoke an internal functionality of the running process. A new cmd process is created instead.
Think twice before you overwrite an automatic variable (like ERRORLEVEL or TIME) with an environment variable because they won't get updated anymore.

Steffen

Re: On "color" command and errorlevel

Posted: 07 Dec 2020 08:21
by dbenham
Meerkat wrote:
07 Dec 2020 04:59
Today I revisited the amazing %mm% macro
I had completely forgotten about this. It truly is an impressive work.


Dave Benham

Re: On "color" command and errorlevel

Posted: 07 Dec 2020 08:26
by penpen
I actually can't test that, but isn't the set command suppose to do that, if you are using .cmd-files?

Code: Select all

@echo off
color 00
echo(%errorlevel%
set "unused="
echo(%errorlevel%
pause
goto :eof
penpen

Re: On "color" command and errorlevel

Posted: 07 Dec 2020 08:54
by Meerkat
T3RRY wrote:
07 Dec 2020 05:14
However more versatility can be achieved be defining a seperate variable for the error return as used in my findstr colorprint macro

...
@T3RRY I just realized that this is macro, not that usual call "function," so yeah... I think I will just use a separate variable for error number as well.
aGerman wrote:
07 Dec 2020 08:03
A very general approach to change the errorlevel is to use cmd /c exit n with n the errorlevel value you want to set. However, I suspect this is slow because it doesn't just invoke an internal functionality of the running process. A new cmd process is created instead.
Think twice before you overwrite an automatic variable (like ERRORLEVEL or TIME) with an environment variable because they won't get updated anymore.

Steffen
Noted. In my PC, cmd /c exit n is even faster than color (w/o parameters)!
penpen wrote:
07 Dec 2020 08:26
I actually can't test that, but isn't the set command suppose to do that, if you are using .cmd-files?

Code: Select all

@echo off
color 00
echo(%errorlevel%
set "unused="
echo(%errorlevel%
pause
goto :eof
penpen
Yeah it works in .cmd files only. I just read now the SS64 entry for errorlevel, and handling errorlevel is one where .bat and .cmd differs. The %mm% though uses the color command for setting errorlevel 0/1, but it fails when the script is opened by double-click (for both .bat and .cmd). That's weird.

Meerkat

Re: On "color" command and errorlevel

Posted: 07 Dec 2020 11:16
by aGerman
aGerman wrote:
07 Dec 2020 08:03
... overwrite ...
Sorry, I meant "override" (an expression that doesn't have a German equivalent, which might be the reason why I often mess it up ...). I was referring to the set "errorlevel=0" you mentioned. This creates an environment variable with the same name, having higher priority than the automatic errorlevel variable.

Steffen

Re: On "color" command and errorlevel

Posted: 10 Dec 2020 01:09
by penpen
This might work for both .bat and .cmd (if you don't need any command line arguments for your batch):

Code: Select all

@echo off
setlocal enableExtensions disableDelayedExpansion
if "%~1" == "" call :init
goto %~1 :eof

:init
%ComSpec% /k  ""%~f0" ":main" & exit"
goto :eof

:main
color 00
echo(%errorlevel%
color
echo(%errorlevel%
pause
goto :eof

penpen