Best way to use xterm ESC-sequences in scripts in Cmd e.g. bat, js, vbs, pl, py? #51

Closed
opened 2026-01-30 21:40:40 +00:00 by claunia · 17 comments
Owner

Originally created by @mobluse on GitHub (Jan 21, 2018).

  • Your Windows build number:
    Microsoft Windows [Version 10.0.17074.1002]

  • What you're doing and what's happening:
    I want to use ESC-sequences in bat-, js-, vbs, pl, py-files in Cmd, but don't know how to switch so that they are used. I tried e.g. a program called input.js:

WScript.Echo("\x1B[1mEnter something\x1B[0m");
WScript.Echo("You entered " + WScript.StdIn.ReadLine());

And run it using cscript input.js //NoLogo. This prints:

Enter something
hello
You entered hello

  • What's wrong / what should be happening instead:
    Enter something
    hello
    You entered hello

I can cure this by using start /wait /b before the command:
start /wait /b cscript input.js //NoLogo
Enter something
hello
You entered hello

Is start /wait /b the best way to use ESC-sequences from https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences in a bat-, js- or vbs-program?

Originally created by @mobluse on GitHub (Jan 21, 2018). * Your Windows build number: Microsoft Windows [Version 10.0.17074.1002] * What you're doing and what's happening: I want to use ESC-sequences in bat-, js-, vbs, pl, py-files in Cmd, but don't know how to switch so that they are used. I tried e.g. a program called input.js: ``` WScript.Echo("\x1B[1mEnter something\x1B[0m"); WScript.Echo("You entered " + WScript.StdIn.ReadLine()); ``` And run it using `cscript input.js //NoLogo`. This prints: ``` Enter something hello You entered hello ``` * What's wrong / what should be happening instead: **`Enter something`** `hello` `You entered hello` I can cure this by using `start /wait /b` before the command: `start /wait /b cscript input.js //NoLogo` **`Enter something`** `hello` `You entered hello` Is `start /wait /b` the best way to use ESC-sequences from https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences in a bat-, js- or vbs-program?
claunia added the Product-ConhostIssue-QuestionArea-VTResolution-Answered labels 2026-01-30 21:40:40 +00:00
Author
Owner

@zadjii-msft commented on GitHub (Jan 22, 2018):

As discussed in the linked docs page, you need to be able to SetConsoleMode with ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 to let the console interpret VT sequences.

How you call that API probably differs from one language to the next. I know that if you try and emit VT inside of a batch script, it will work just fine (because cmd.exe already sets that flag for itself). I don't know how you'd set it it JS or VBS. I do know how to do it in python however, see this file.

I would say that the whole start /wait /b strategy is probably not the way to go about this solution.

@zadjii-msft commented on GitHub (Jan 22, 2018): As discussed in the linked docs page, you need to be able to [SetConsoleMode](https://docs.microsoft.com/en-us/windows/console/setconsolemode) with **ENABLE_VIRTUAL_TERMINAL_INPUT** 0x0200 to let the console interpret VT sequences. How you call that API probably differs from one language to the next. I know that if you try and emit VT inside of a batch script, it will work just fine (because cmd.exe already sets that flag for itself). I don't know how you'd set it it JS or VBS. I do know how to do it in python however, see [this file](https://github.com/zadjii/win-py-vt/blob/master/enable.py). I would say that the whole `start /wait /b` strategy is probably not the way to go about this solution.
Author
Owner

@mobluse commented on GitHub (May 3, 2018):

I think that cscript and curl should set that flag so that you can use xterm ESC-sequences with them.

Now you have to use this in Cmd.exe:
chcp 65001 | start /wait /b curl http://wttr.in/lund

But if that flag was set you could just use:
chcp 65001 | curl http://wttr.in/lund

@mobluse commented on GitHub (May 3, 2018): I think that `cscript` and `curl` should set that flag so that you can use xterm ESC-sequences with them. Now you have to use this in Cmd.exe: `chcp 65001 | start /wait /b curl http://wttr.in/lund` But if that flag was set you could just use: `chcp 65001 | curl http://wttr.in/lund`
Author
Owner

@zadjii-msft commented on GitHub (May 3, 2018):

cough @bitcrazed

We actually had a discussion about enabling the ENABLE_VIRTUAL_TERMINAL_INPUT flag in curl around here a few weeks back, after we started including it inbox. (IIRC) The discussion eventually came to the conclusion that someone would need to make a PR to the curl source itself to enable that flag for it's Windows implementation, and then we'd be able to take it from there.

@zadjii-msft commented on GitHub (May 3, 2018): *cough* @bitcrazed We actually had a discussion about enabling the ENABLE_VIRTUAL_TERMINAL_INPUT flag in curl around here a few weeks back, after we started including it inbox. (IIRC) The discussion eventually came to the conclusion that someone would need to make a PR to the curl source itself to enable that flag for it's Windows implementation, and then we'd be able to take it from there.
Author
Owner

@bitcrazed commented on GitHub (May 3, 2018):

Happy to revisit after Build ;)

@bitcrazed commented on GitHub (May 3, 2018): Happy to revisit after Build ;)
Author
Owner

@driver1998 commented on GitHub (Jun 28, 2018):

how about a command in cmd (like setlocal enableVirtualTerminal) to help set the flag in batch scripts or other scripts?

Update: Well I totally forgot that CMD enabled that feature by default.
But you'll need to add the actual ESC byte (0x27) in the echo commands.

@driver1998 commented on GitHub (Jun 28, 2018): how about a command in cmd (like `setlocal enableVirtualTerminal`) to help set the flag in batch scripts or other scripts? Update: Well I totally forgot that CMD enabled that feature by default. But you'll need to add the actual ESC byte (0x27) in the echo commands.
Author
Owner

@zadjii-msft commented on GitHub (Jul 2, 2018):

For the record, you can totally just embed the actual ESC character in a bat file, and it'll work as you expect when you run it. EX:

@echo off
if (%1)==() (goto :usage)
if (%2)==() (goto :usage)
if (%3)==() (goto :usage)

echo ]12;rgb:%1/%2/%3
goto :EOF

:usage
echo Usage: cursor-color ^<red^> ^<green^> ^<blue^>
echo     where red, green, blue are color components in hex
echo     Ex: cursor-color FF 00 FF will set the cursor to Magenta
echo:

:EOF

(admittedly, that'll only set cursor colors on insiders)

@zadjii-msft commented on GitHub (Jul 2, 2018): For the record, you can totally just embed the actual ESC character in a bat file, and it'll work as you expect when you run it. EX: ``` bat @echo off if (%1)==() (goto :usage) if (%2)==() (goto :usage) if (%3)==() (goto :usage) echo ]12;rgb:%1/%2/%3 goto :EOF :usage echo Usage: cursor-color ^<red^> ^<green^> ^<blue^> echo where red, green, blue are color components in hex echo Ex: cursor-color FF 00 FF will set the cursor to Magenta echo: :EOF ``` (admittedly, that'll only set cursor colors on insiders)
Author
Owner

@PhMajerus commented on GitHub (Jul 5, 2018):

For CUI WSH (JScript, VBScript, and others in cscript.exe), you don't need to update WSH itself, all you need is an automation object that lets you control the console configuration.

I built one that can not only toggle the VT processing, but get/set the input and output codepages, cursor size, buffer and window size, window title, colors palette, etc...

vt in wsh

See VBScript source at https://gist.github.com/PhMajerus/e80334f1a04ad276d5f4e563ce30357d

The automation component is currently bundled with my ActiveScript Shell and PowerShell Tools, but Web site is temporarily offline. If anyone wants, I can post them somewhere alse.

@PhMajerus commented on GitHub (Jul 5, 2018): For CUI WSH (JScript, VBScript, and others in cscript.exe), you don't need to update WSH itself, all you need is an automation object that lets you control the console configuration. I built one that can not only toggle the VT processing, but get/set the input and output codepages, cursor size, buffer and window size, window title, colors palette, etc... ![vt in wsh](https://user-images.githubusercontent.com/25664275/42343741-50f6c70a-809a-11e8-8771-08f525a4754e.png) See VBScript source at https://gist.github.com/PhMajerus/e80334f1a04ad276d5f4e563ce30357d The automation component is currently bundled with my ActiveScript Shell and PowerShell Tools, but Web site is temporarily offline. If anyone wants, I can post them somewhere alse.
Author
Owner

@ExE-Boss commented on GitHub (Aug 30, 2018):

@mobluse In PowerShell, you can do curl http://wttr.in/lund 2>&1 to force parsing of the output with support for VT escapes (I used to do so with the output of more.com before I installed less for Windows).

@ExE-Boss commented on GitHub (Aug 30, 2018): @mobluse In PowerShell, you can do `curl http://wttr.in/lund 2>&1` to force parsing of the output with support for VT escapes (I used to do so with the output of `more.com` before I installed [`less` for Windows](https://chocolatey.org/packages/less)).
Author
Owner

@mobluse commented on GitHub (Sep 10, 2018):

@ExE-Boss That doesn't work at all here. E.g. curl uses the internal curl for PowerShell, and when I use curl.exe I still only get uninterpreted escape codes, even though 2>&1.

@mobluse commented on GitHub (Sep 10, 2018): @ExE-Boss That doesn't work at all here. E.g. curl uses the internal curl for PowerShell, and when I use curl.exe I still only get uninterpreted escape codes, even though 2>&1.
Author
Owner

@ExE-Boss commented on GitHub (Sep 10, 2018):

@mobluse I’m talking about PowerShell Core 6, which no longer has the curl to Invoke-WebRequest alias (it works for me even if I do curl.exe http://wttr.in/lund 2>&1 (referring to the curl that ships with Windows 10)).

@ExE-Boss commented on GitHub (Sep 10, 2018): @mobluse I’m talking about PowerShell Core 6, which no longer has the `curl` to `Invoke-WebRequest` alias (it works for me even if I do `curl.exe http://wttr.in/lund 2>&1` (referring to the curl that ships with Windows&nbsp;10)).
Author
Owner

@miniksa commented on GitHub (May 29, 2019):

This appears to be answered and curl (linked issue) appears to have merged this change. Closing.

@miniksa commented on GitHub (May 29, 2019): This appears to be answered and curl (linked issue) appears to have merged this change. Closing.
Author
Owner

@rbeesley commented on GitHub (Jun 20, 2019):

For cmd, I like to set a variable:

:: Escape Code - %ESC% will have the value of "<ESC>" (0x1B).
SET ESC=

Then set my CSI:

:: Control Sequence Introducer - %CSI% is "<ESC>[" (0x1B 0x5B).
SET CSI=%ESC%[

Then you can use %ESC% and %CSI%. For example from the what zadjii-msft posted:

echo %CSI%12;rgb:%1/%2/%3%ESC%

You still have the unprintable character, but it only needs to be written once and can be documented.

@rbeesley commented on GitHub (Jun 20, 2019): For cmd, I like to set a variable: ```Batch :: Escape Code - %ESC% will have the value of "<ESC>" (0x1B). SET ESC= ``` Then set my CSI: ```Batch :: Control Sequence Introducer - %CSI% is "<ESC>[" (0x1B 0x5B). SET CSI=%ESC%[ ``` Then you can use %ESC% and %CSI%. For example from the what zadjii-msft posted: ```Batch echo %CSI%12;rgb:%1/%2/%3%ESC% ``` You still have the unprintable <ESC> character, but it only needs to be written once and can be documented.
Author
Owner

@oising commented on GitHub (Jun 20, 2019):

Here's a way in pure cmd that avoids you having to figure out how to insert invisible, unprintable characters:

@echo off & setlocal & setlocal enabledelayedexpansion
for /f "tokens=* delims=" %%a in ('forfiles /p %~dps0 /m %~nxs0 /c "cmd /c echo.0x1B0x07"') do @set arrChar=%%a
set ESC=!arrChar:~0,1!
set ST=!arrChar:~1,1!  

REM rest of script...

forfiles.exe (windows built-in) will do 0xNN replacement with character literals.

@oising commented on GitHub (Jun 20, 2019): Here's a way in pure cmd that avoids you having to figure out how to insert invisible, unprintable characters: ```cmd @echo off & setlocal & setlocal enabledelayedexpansion for /f "tokens=* delims=" %%a in ('forfiles /p %~dps0 /m %~nxs0 /c "cmd /c echo.0x1B0x07"') do @set arrChar=%%a set ESC=!arrChar:~0,1! set ST=!arrChar:~1,1! REM rest of script... ``` `forfiles.exe` (windows built-in) will do 0xNN replacement with character literals.
Author
Owner

@ExE-Boss commented on GitHub (Jun 22, 2019):

Or, you could just do Alt+027 for ESC and Alt+07 for ST.

@ExE-Boss commented on GitHub (Jun 22, 2019): Or, you&nbsp;could just do&nbsp;<kbd>Alt+027</kbd> for&nbsp;`ESC` and&nbsp;<kbd>Alt+07</kbd> for&nbsp;`ST`.
Author
Owner

@DHowett commented on GitHub (Jun 13, 2020):

@nu8 this issue has nothing to do with curl?

@DHowett commented on GitHub (Jun 13, 2020): @nu8 this issue has nothing to do with curl?
Author
Owner

@mike-clark-8192 commented on GitHub (Mar 8, 2024):

I wrote this batch file to test scrollback clearing in VSCode (which is currently kind of buggy), but it also demonstrates outputting a lot of (all?) the core foreground and background colors. It has no dependencies and the source contains no control characters:

@echo off
setlocal enableextensions

call :testit "[3J" "erase scrollback"         || exit /b
call :testit "[2J" "erase all"                || exit /b
call :testit "[1J" "erase above"              || exit /b
call :testit "[0J" "erase below"              || exit /b
call :testit "[J"  "erase below (alternate)"  || exit /b
call :testit "c"   "reset term"               || exit /b
echo Done.

goto :eof
:testit
REM this loop will probably reach the scrollback on most window sizes
for /l %%F in (30,1,37) do (
    for /l %%B in (40,1,47) do (
        call :echoe "\x1b[%%F;%%Bm%%F;%%B\x1b[0m"
    )
)
echo. & echo.
set /p "_=Press enter to test %1 (%~2): "
if "%_%"=="q" exit /b 1
call :echoe \x1b%1
echo Sending of %1 (%~2) is complete.
if "%~1"=="c" exit /b && REM "(exit because c is the last test)"
set /p "_=Press enter to move on to the next test."
exit /b 0
goto :eof

goto :eof
:echoe
setlocal
set "arg=%~1"
set "arg=%arg:\x=0x%"
forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c <nul set /p _=%arg%"
goto :eof
@mike-clark-8192 commented on GitHub (Mar 8, 2024): I wrote this batch file to test scrollback clearing in VSCode (which is currently kind of buggy), but it also demonstrates outputting a lot of (all?) the core foreground and background colors. It has no dependencies and the source contains no control characters: ```bat @echo off setlocal enableextensions call :testit "[3J" "erase scrollback" || exit /b call :testit "[2J" "erase all" || exit /b call :testit "[1J" "erase above" || exit /b call :testit "[0J" "erase below" || exit /b call :testit "[J" "erase below (alternate)" || exit /b call :testit "c" "reset term" || exit /b echo Done. goto :eof :testit REM this loop will probably reach the scrollback on most window sizes for /l %%F in (30,1,37) do ( for /l %%B in (40,1,47) do ( call :echoe "\x1b[%%F;%%Bm%%F;%%B\x1b[0m" ) ) echo. & echo. set /p "_=Press enter to test %1 (%~2): " if "%_%"=="q" exit /b 1 call :echoe \x1b%1 echo Sending of %1 (%~2) is complete. if "%~1"=="c" exit /b && REM "(exit because c is the last test)" set /p "_=Press enter to move on to the next test." exit /b 0 goto :eof goto :eof :echoe setlocal set "arg=%~1" set "arg=%arg:\x=0x%" forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c <nul set /p _=%arg%" goto :eof ```
Author
Owner

@rbeesley commented on GitHub (Mar 8, 2024):

@mike-clark-8192 oh, that's a technique I didn't know. I didn't know you could use forfiles like that, although it is in the documentation.

@rbeesley commented on GitHub (Mar 8, 2024): @mike-clark-8192 oh, that's a technique I didn't know. I didn't know you could use forfiles like that, although it is in the documentation.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#51