¿Cómo tener varios colores en un archivo por lotes de Windows?

Resuelto daniel11 asked hace 14 años • 14 respuestas

Me preguntaba si es posible tener texto de diferentes colores en la misma línea en un archivo por lotes de Windows, por ejemplo si dice

echo hi world

Quiero que "hola" sea de un color y "mundo" sea de otro color. Tal vez podría configurar el comando COLOR como una variable:

set color1= color 2
set color9= color A

y luego desplegarlos a ambos en la misma línea junto con

echo hi world

pero no sé cómo haría eso.

daniel11 avatar Dec 03 '10 03:12 daniel11
Aceptado

Puede realizar salidas multicolores sin ningún programa externo.

@echo off
SETLOCAL EnableDelayedExpansion
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
  set "DEL=%%a"
)
echo say the name of the colors, don't read

call :ColorText 0a "blue"
call :ColorText 0C "green"
call :ColorText 0b "red"
echo(
call :ColorText 19 "yellow"
call :ColorText 2F "black"
call :ColorText 4e "white"

goto :eof

:ColorText
echo off
<nul set /p ".=%DEL%" > "%~2"
findstr /v /a:%1 /R "^$" "%~2" nul
del "%~2" > nul 2>&1
goto :eof

Utiliza la función de color del comando findtr.

Findstr se puede configurar para generar números de línea o nombres de archivos en un color definido.
Entonces, primero creo un archivo con el texto como nombre de archivo y el contenido es de un solo <backspace>carácter (ASCII 8).
Luego busco todas las líneas que no están vacías en el archivo y en nul, por lo que el nombre del archivo se mostrará en el color correcto agregado con dos puntos, pero los dos puntos se eliminan inmediatamente mediante el archivo <backspace>.

EDITAR: Un año después... todos los caracteres son válidos

@echo off
setlocal EnableDelayedExpansion
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
  set "DEL=%%a"
)

rem Prepare a file "X" with only one dot
<nul > X set /p ".=."

call :color 1a "a"
call :color 1b "b"
call :color 1c "^!<>&| %%%%"*?"
exit /b

:color
set "param=^%~2" !
set "param=!param:"=\"!"
findstr /p /A:%1 "." "!param!\..\X" nul
<nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"
exit /b

Esto utiliza la regla para rutas/nombres de archivo válidos.
Si \..\hay a en la ruta, el elemento prefijado se eliminará por completo y no es necesario que este elemento contenga solo caracteres de nombre de archivo válidos.

jeb avatar Mar 17 '2011 20:03 jeb

La respuesta editada de Jeb se acerca a resolver todos los problemas. Pero tiene problemas con las siguientes cadenas:

"a\b\"
"a/b/"
"\"
"/"
"."
".."
"c:"

Modifiqué su técnica a algo que creo que realmente puede manejar cualquier cadena de caracteres imprimibles, excepto las limitaciones de longitud.

Otras mejoras:

  • Utiliza la ubicación %TEMP% para el archivo temporal, por lo que ya no necesita acceso de escritura al directorio actual.

  • Se crearon 2 variantes, una toma un literal de cadena y la otra el nombre de una variable que contiene la cadena. La versión variable es generalmente menos conveniente, pero elimina algunos problemas de escape de caracteres especiales.

  • Se agregó la opción /n como tercer parámetro opcional para agregar una nueva línea al final de la salida.

La tecla de retroceso no funciona en un salto de línea, por lo que la técnica puede tener problemas si la línea se ajusta. Por ejemplo, imprimir una cadena con una longitud entre 74 y 79 no funcionará correctamente si la consola tiene un ancho de línea de 80.

@echo off
setlocal

call :initColorPrint

call :colorPrint 0a "a"
call :colorPrint 0b "b"
set "txt=^" & call :colorPrintVar 0c txt
call :colorPrint 0d "<"
call :colorPrint 0e ">"
call :colorPrint 0f "&"
call :colorPrint 1a "|"
call :colorPrint 1b " "
call :colorPrint 1c "%%%%"
call :colorPrint 1d ^"""
call :colorPrint 1e "*"
call :colorPrint 1f "?"
call :colorPrint 2a "!"
call :colorPrint 2b "."
call :colorPrint 2c ".."
call :colorPrint 2d "/"
call :colorPrint 2e "\"
call :colorPrint 2f "q:" /n
echo(
set complex="c:\hello world!/.\..\\a//^<%%>&|!" /^^^<%%^>^&^|!\
call :colorPrintVar 74 complex /n

call :cleanupColorPrint

exit /b

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:colorPrint Color  Str  [/n]
setlocal
set "str=%~2"
call :colorPrintVar %1 str %3
exit /b

:colorPrintVar  Color  StrVar  [/n]
if not defined %~2 exit /b
setlocal enableDelayedExpansion
set "str=a%DEL%!%~2:\=a%DEL%\..\%DEL%%DEL%%DEL%!"
set "str=!str:/=a%DEL%/..\%DEL%%DEL%%DEL%!"
set "str=!str:"=\"!"
pushd "%temp%"
findstr /p /A:%1 "." "!str!\..\x" nul
if /i "%~3"=="/n" echo(
exit /b

:initColorPrint
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do set "DEL=%%a"
<nul >"%temp%\x" set /p "=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%.%DEL%"
exit /b

:cleanupColorPrint
del "%temp%\x"
exit /b


ACTUALIZACIÓN 2012-11-27

Este método falla en XP porque FINDSTR muestra el retroceso como un punto en la pantalla. La respuesta original de Jeb funciona en XP, aunque con las limitaciones ya señaladas.


ACTUALIZACIÓN 2012-12-14

Ha habido mucha actividad de desarrollo en DosTips y SS64 . Resulta que FINDSTR también daña los nombres de archivos que contienen ASCII extendido si se proporcionan en la línea de comando. He actualizado mis preguntas y respuestas de FINDSTR .

A continuación se muestra una versión que funciona en XP y admite TODOS los caracteres de un solo byte excepto 0x00 (nul), 0x0A (salto de línea) y 0x0D (retorno de carro). Sin embargo, cuando se ejecuta en XP, la mayoría de los caracteres de control se mostrarán como puntos. Esta es una característica inherente de FINDSTR en XP que no se puede evitar.

Desafortunadamente, agregar soporte para XP y caracteres ASCII extendidos ralentiza la rutina :-(

Sólo por diversión, tomé algo de arte ASCII en color de la Galería de arte ASCII de Joan Stark y lo adapté para usarlo con ColorPrint. Agregué un punto de entrada :c solo para taquigrafía y para manejar un problema con las comillas literales.

@echo off
setlocal disableDelayedExpansion
set q=^"
echo(
echo(
call :c 0E "                ,      .-;" /n
call :c 0E "             ,  |\    / /  __," /n
call :c 0E "             |\ '.`-.|  |.'.-'" /n
call :c 0E "              \`'-:  `; : /" /n
call :c 0E "               `-._'.  \'|" /n
call :c 0E "              ,_.-=` ` `  ~,_" /n
call :c 0E "               '--,.    "&call :c 0c ".-. "&call :c 0E ",=!q!." /n
call :c 0E "                 /     "&call :c 0c "{ "&call :c 0A "* "&call :c 0c ")"&call :c 0E "`"&call :c 06 ";-."&call :c 0E "}" /n
call :c 0E "                 |      "&call :c 0c "'-' "&call :c 06 "/__ |" /n
call :c 0E "                 /          "&call :c 06 "\_,\|" /n
call :c 0E "                 |          (" /n
call :c 0E "             "&call :c 0c "__ "&call :c 0E "/ '          \" /n
call :c 02 "     /\_    "&call :c 0c "/,'`"&call :c 0E "|     '   "&call :c 0c ".-~!q!~~-." /n
call :c 02 "     |`.\_ "&call :c 0c "|   "&call :c 0E "/  ' ,    "&call :c 0c "/        \" /n
call :c 02 "   _/  `, \"&call :c 0c "|  "&call :c 0E "; ,     . "&call :c 0c "|  ,  '  . |" /n
call :c 02 "   \   `,  "&call :c 0c "|  "&call :c 0E "|  ,  ,   "&call :c 0c "|  :  ;  : |" /n
call :c 02 "   _\  `,  "&call :c 0c "\  "&call :c 0E "|.     ,  "&call :c 0c "|  |  |  | |" /n
call :c 02 "   \`  `.   "&call :c 0c "\ "&call :c 0E "|   '     "&call :c 0A "|"&call :c 0c "\_|-'|_,'\|" /n
call :c 02 "   _\   `,   "&call :c 0A "`"&call :c 0E "\  '  . ' "&call :c 0A "| |  | |  |           "&call :c 02 "__" /n
call :c 02 "   \     `,   "&call :c 0E "| ,  '    "&call :c 0A "|_/'-|_\_/     "&call :c 02 "__ ,-;` /" /n
call :c 02 "    \    `,    "&call :c 0E "\ .  , ' .| | | | |   "&call :c 02 "_/' ` _=`|" /n
call :c 02 "     `\    `,   "&call :c 0E "\     ,  | | | | |"&call :c 02 "_/'   .=!q!  /" /n
call :c 02 "     \`     `,   "&call :c 0E "`\      \/|,| ;"&call :c 02 "/'   .=!q!    |" /n
call :c 02 "      \      `,    "&call :c 0E "`\' ,  | ; "&call :c 02 "/'    =!q!    _/" /n
call :c 02 "       `\     `,  "&call :c 05 ".-!q!!q!-. "&call :c 0E "': "&call :c 02 "/'    =!q!     /" /n
call :c 02 "    jgs _`\    ;"&call :c 05 "_{  '   ; "&call :c 02 "/'    =!q!      /" /n
call :c 02 "       _\`-/__"&call :c 05 ".~  `."&call :c 07 "8"&call :c 05 ".'.!q!`~-. "&call :c 02 "=!q!     _,/" /n
call :c 02 "    __\      "&call :c 05 "{   '-."&call :c 07 "|"&call :c 05 ".'.--~'`}"&call :c 02 "    _/" /n
call :c 02 "    \    .=!q!` "&call :c 05 "}.-~!q!'"&call :c 0D "u"&call :c 05 "'-. '-..'  "&call :c 02 "__/" /n
call :c 02 "   _/  .!q!    "&call :c 05 "{  -'.~('-._,.'"&call :c 02 "\_,/" /n
call :c 02 "  /  .!q!    _/'"&call :c 05 "`--; ;  `.  ;" /n
call :c 02 "   .=!q!  _/'      "&call :c 05 "`-..__,-'" /n
call :c 02 "    __/'" /n
echo(

exit /b

:c
setlocal enableDelayedExpansion
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:colorPrint Color  Str  [/n]
setlocal
set "s=%~2"
call :colorPrintVar %1 s %3
exit /b

:colorPrintVar  Color  StrVar  [/n]
if not defined DEL call :initColorPrint
setlocal enableDelayedExpansion
pushd .
':
cd \
set "s=!%~2!"
:: The single blank line within the following IN() clause is critical - DO NOT REMOVE
for %%n in (^"^

^") do (
  set "s=!s:\=%%~n\%%~n!"
  set "s=!s:/=%%~n/%%~n!"
  set "s=!s::=%%~n:%%~n!"
)
for /f delims^=^ eol^= %%s in ("!s!") do (
  if "!" equ "" setlocal disableDelayedExpansion
  if %%s==\ (
    findstr /a:%~1 "." "\'" nul
    <nul set /p "=%DEL%%DEL%%DEL%"
  ) else if %%s==/ (
    findstr /a:%~1 "." "/.\'" nul
    <nul set /p "=%DEL%%DEL%%DEL%%DEL%%DEL%"
  ) else (
    >colorPrint.txt (echo %%s\..\')
    findstr /a:%~1 /f:colorPrint.txt "."
    <nul set /p "=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"
  )
)
if /i "%~3"=="/n" echo(
popd
exit /b


:initColorPrint
for /f %%A in ('"prompt $H&for %%B in (1) do rem"') do set "DEL=%%A %%A"
<nul >"%temp%\'" set /p "=."
subst ': "%temp%" >nul
exit /b


:cleanupColorPrint
2>nul del "%temp%\'"
2>nul del "%temp%\colorPrint.txt"
>nul subst ': /d
exit /b
dbenham avatar May 02 '2012 04:05 dbenham