There are a couple solutions.
carlos' color v23c
Playing around with it it has some strange outputs. Test using
call :color 04 "Test poison '&|<>!()" \n
call :color 06 ""
call :color 0A " can be printed if you use empty strings" \n
produced (german console):
">" kann syntaktisch an dieser Stelle nicht verarbeitet werden.
" can be printed if you use empty strings
it produces some major errors sometimes and is a bit slow...
VT100 alternative (Win10+)
@echo off
for /f "delims=" %%E in ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x1B"') do (
set "ESC=%%E["
)
call :vtEcho 93 "No escaping needed for most characters: '&|<>!()"
call :vtEcho 94 "Problems occur with '^' and '"' though"
:vtEcho [VT100 colorcode] [message]
<NUL set /P "=%ESC%%1m%~2%ESC%0m"
echo+
exit /B 0
Output:
No escaping needed for most characters: '&|<>!()
Problems occur with '^^' and '"'
So how does this work? Basically echoing using set /P
solves almost every poison character, and VT sequences make the color using the color codes. We first generate the ESC
character using forfiles and then use it in the function. But since we try to give this as a single flag to a subroutine we need to double quote it... and that means we have problems displaying that. Also set /P
can only print single ^
if you make it <NUL set /P^"=^^"
, which will fail in any other case.
Workaround for "
and ^
using flag shifting:
:vtEcho [VT100 colorcode] [message] [message] [message] ...
:: Use """" for displaying a '"'
:: Use "^" for displaying a '^'
:: Use "\n" to make a new line
<NUL set /P "=%ESC%%1m"
:__vtEcho
shift
if not "%~1" == "" (
if "%~1" == """" (
<NUL set /P ^"="""^"
goto __vtEcho
)
if "%~1" == "^^" (
<NUL set /P ^"=^^"
goto __vtEcho
)
if "%~1" == "\n" (
echo+
goto __vtEcho
)
<NUL set /P "=%~1"
goto __vtEcho
)
echo %ESC%0m
exit /B 0
Test with:
call :vtEcho 96 "No problems with '" """" "' and '" "^" "' and has" \n "support for '\n'"`
result in:
No problems with '"' and '^' and has
support for '\n'
To compensate for "
and ^
we check the individual parts of the flags if they are their wrong counterpart (""
/ ^^
) and print the right output instead.
HOWEVER
Using set /P
makes it so you cannot start your line with spaces. To do this there is no nice wrapper function. If you dont need that you can use disappearing qoutes:
@echo off
set ""="
for /f "delims=" %%E in ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x1B"') do (
set "BLUE=echo !"!%%E[94m"
set "CYAN=echo !"!%%E[96m"
set "END=%%E[0m"
)
setlocal EnableDelayedExpansion
%BLUE%Has no problems with '&|<>" characters%END%
%CYAN%'^^' and "^^!" need to be escaped%END%
Results in:
Has no problems with '&|<>" characters
'^' and "!" need to be escaped
I hope you are able to make something out of this. Thx for reading
References: