Sep 022015
 

colorecho logoRecently, I am doing a lot of audio/video transcoding, and for that I’m using tools like mkvextract, mkvmerge, x264, avconv and fghaacenc on the command line. Mostly this is to get rid of old files that are either very inefficiently encoded – like DivX3 or MPEG-2 – or are just too large/high-bitrate for what the content’s worth. Since I do have large batches of relatively similar files, I wrote myself a few nice loops that would walk through an entire stack of videos and process all of it automatically. Because I want to see at first glance how far through a given video stack a script is, I wanted to output some colored notifications on the shell after each major processing step, telling me the current video number. That way, I could easily see how far the job had progressed. We’re talking processes here that take multiple days, so it makes sense.

Turns out that this was harder than expected. In the old DOS days, you would just load ANSI.SYS for that, and get ANSI color codes to work with. The same codes still work in modern UNIX terminals. But not within the Windows cmd for whatever reason. Now there is an interface for that kind of stuff, but seemingly no tools to use it. Like e.g. the echo command simply can’t make use of it.

Now there is project porting ANSI codes back to the cmd, and it’s called [ANSICON]. Basically just a DLL hooked into the cmd. Turns out I can’t use that, because I’m already using [clink] to make my cmd more UNIX-like and actually usable, which also is additional code hooked into the cmd, and the two confict with each other. More information about that [here].

So how the hell can I do this then? Turns out there is a batch script that can do it, but it’s a very outlandish hack that doesn’t seem to want to play nice with my shells if I do @echo off instead of echo off as well. I guess it’s clinks work breaking stuff here, but I’m not sure. Still, here is the code, as found by [Umlüx]:

expand/collapse source code
  1. ECHO OFF
  2. SETLOCAL EnableDelayedExpansion
  3.  
  4. FOR /F "tokens=1,2 delims=#" %%A IN ('"PROMPT #$H#$E# & ECHO ON & FOR %%b IN (1) DO REM"') DO (
  5.   SET "DEL=%%A"
  6. )
  7.  
  8. ECHO say the name of the colors, dont read
  9.  
  10. CALL :ColorText 0a "blue"
  11. CALL :ColorText 0C "green"
  12. CALL :ColorText 0b "red"
  13. ECHO.
  14. CALL :ColorText 19 "yellow"
  15. CALL :ColorText 2F "black"
  16. CALL :ColorText 4e "white"
  17.  
  18. GOTO :eof
  19.  
  20. :ColorText
  21.  
  22. ECHO OFF
  23.  
  24.  "%~2"
  25. findstr /v /a:%1 /R "^$" "%~2" NUL
  26. DEL "%~2" > NUL 2>&1
  27.  
  28. GOTO :eof

So since those two solutions didn’t work for me, what else could I try?

Then I had that crazy idea: Since the interface is there, why not write a little C program (actually ended up being C++ instead) that uses it? Since I was on Linux at the time, I tried to write it there and attempt my first cross-compile for Windows using a pre-built [MinGW-w64] compiler, that luckily just played along nicely on my CentOS 6.6 Linux. You can get pre-built binaries for 32-Bit Windows targets [here], and for 64-bit Windows targets [here]. Thing is, I know zero C++, so that took some time and it’s quite crappy, but here’s the code:

expand/collapse source code
  1. #include <iostream>
  2. #include "windows.h"
  3.  
  4. // Set NT commandline color:
  5. void SetColor(int value) {
  6.     SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), value);
  7. }
  8.  
  9. int main(int argc, char *argv[]) {
  10.   SetColor(atoi(argv[2]));
  11.   std::cout << "\r\n" << argv[1] << "\r\n";
  12.   SetColor(7);
  13.   return 0;
  14. }

Update 2016-06-22: Since I wanted to work with wide character strings in recent days (so, non-ANSI Unicode characters), my colorecho command failed, because it couldn’t handle them at all. There was no wide character support. I decided to update the program to also work with that using Windows-typical UCS-2le/UTF-16, here’s the code:

expand/collapse source code
  1. #include <iostream>
  2. #include <io.h>
  3. #include <fcntl.h>
  4. #include "windows.h"
  5.  
  6. // Set NT commandline color:
  7. void SetColor(int value) {
  8.     SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), value);
  9. }
  10.  
  11. // Unicode main
  12. int wmain(int argc, wchar_t *argv[]) {
  13.   SetColor(_wtoi(argv[2]));
  14.   _setmode(_fileno(stdout), _O_U16TEXT);      // Set stdout to UCS-2le/UTF-16
  15.   std::wcout << "\r\n" << argv[1] << "\r\n";  // Write unicode
  16.   SetColor(7);                                // Set color back to default
  17.   return 0;
  18. }

I also updated the download section and the screenshots further below. End of update.

This builds nicely using MinGW on Linux for 64-bit Windows targets. Like so: While sitting in the MinGW directory (I put my code there as echo.cpp as well, for simplicities’ sake), run: ./bin/x86_64-w64-mingw32-g++ echo.cpp -o colorecho-x86_64.exe. If you want to target 32-bit Windows instead, you’d need to use the proper MinGW for that (it comes in a separate archive): ./bin/i686-w64-mingw32-g++ echo.cpp -o colorecho-x86_64.exe

When building like that, you’d also need to deploy libstdc++-6.so and libgcc_s_seh-1.dll along with the EXE files though. The DLLs can be obtained from your local MinGW installation directory, subfolder ./x86_64-w64-mingw32/lib/ for the 64-bit or ./i686-w64-mingw32/lib/ for the 32-bit compiler. If you don’t want to do that and rather rely on Microsofts own C++ redistributables, you can also compile it with Microsoft VisualStudio Express, using its pre-prepared command line. You can find that here, if you have Microsofts VisualStudio installed – version 2010 in my case:

VC2010 command lines

The command lines of Visual Studio (click to enlarge)

Here, the “Visual Studio Command Prompt” is for a 32-bit build target, and “Visual Studio x64 Win64 Command Prompt” is for building 64-bit command line programs. Choose the appropriate one, then change into a directory where you have echo.cpp and run the following command: cl /EHsc /W4 /nologo /Fecolorecho.exe echo.cpp, giving you the executable colorecho.exe.

Alternatively, you can just download my pre-compiled versions here:

Update 2016-06-22: And here are the Unicode versions:

End of update.

Note that this tool does exactly what I need it to do, but it’ll likely not do exactly what you’d need it to do. Like e.g. the line breaks it adds before and after its output. That’s actually a job for the shells echo command to do, not some command line tool. But I just don’t care. So that’s why it’s basically a piece of crap for general use. The syntax is as follows, as shown for the 64-bit VC10 build:

colorecho-x86_64-vc10.exe "I am yellow!" 14

When run, it looks like this:

Colorecho running

colorecho invoked on the Windows cmd

So the first parameter is the string to be echoed, the second one is the color number. That number is 2-digit and can affect both the foreground and the background. Here the first 16 of them, which are foreground only:

  • 0: Black
  • 1: Dark blue
  • 2: Dark green
  • 3: Dark cyan
  • 4: Dark red
  • 5: Dark purple
  • 6: Dark yellow
  • 7: Light grey
  • 8: Dark grey
  • 9: Light blue
  • 10: Light green
  • 11: Light cyan
  • 12: Light red
  • 13: Light purple
  • 14: Light yellow
  • 15: White

If you go higher than that, you’ll also start changing the background colors and you’ll get different combinations of foreground and background colorization.

The background colors actually follow the same order, black, dark blue, dark green, etc. Numbers from 0..15 are on black background, numbers from 16..31 are on a dark blue background and so on. This makes up pretty much the same list:

  • 0..15: 16 foreground colors as listed above on the default black background, and
  • 16..31: on a dark blue background
  • 32..47: on a dark green background
  • 48..63: on a dark cyan background
  • 64..79: on a dark red background
  • 80..95: ona dark purple background
  • 96..111: on a dark yellow background
  • 112..127: on a light grey background
  • 128..143: on a dark grey background
  • 144..159: on a light blue background
  • 160..175: on a light green background
  • 176..191: on a light cyan background
  • 192..207: on a light red background
  • 208..223: on a light purple background
  • 224..239: on a light yellow background
  • 240..255: on a white background

Going over 255 will simply result in an overflow causing the system to start from the beginning, so 256 is equal to 0, 257 to 1, 260 to 4 and so on.

Update 2016-06-22: With the Unicode version, you can now even do stupid stuff like this:

colorecho unicode with DejaVu Sans Mono font on Windows cmd

It could be useful for some people? Maybe?

Note that this has been rendered using the DejaVu Sans Mono font, you can get it from [here]. Also, you need to tell the Windows cmd which fonts to allow (only monospaced TTFs work), you can read how to do that [here], it’s a relatively simple registry hack. I have yet to find a font that would work and also render CJK characters though, but with the fonts I myself have available at the moment, asian stuff won’t work, you’ll just get some boxes instead:

colorecho unicode CJK fail

Only characters which have proper glyphs for all desired codepoints in the font in use can be rendered, at least on Windows XP.

Note that this is not a limitation of colorecho, it does output the characters correctly, “ですね” in this case. It’s just that DejaVu Sans Mono has no font glyphs to actually draw them on screen. If you ever come across a neat cmd-terminal-compatible font that can render most symbols and CJK, please tell me in the comments, I’d be quite happy about that! End of update.

If somebody really wants to use this (which I doubt, but hey), but wishes it to do things in a more sane way, just request it in the comments. Or, if you can, just take the code, change and recompile it by yourself. You can get Microsofts VisualStudio Express – in the meantime called [VisualStudio Community] – free of charge anyway, and MinGW is free software to begin with.

CC BY-NC-SA 4.0 How to echo colored text on the Windows command line (cmd.exe) by The GAT at XIN.at is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

  8 Responses to “How to echo colored text on the Windows command line (cmd.exe)”

  1. Hello boy, I found this writing when I have been searching about customize color in cmd, that fortunately I see your c++ code. thank you. It was very useful for me :), of course then I edited it a little. (I am non-native English, EXCUSE me if you see some mistake.)

    #include <iostream>
    #include "windows.h"
    
    // Set NT commandline color:
    void SetColor(int value) {
      SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), value);
    }
    
    int main(int argc, char** argv) {
      ++argv;                /// remove the name of the fine
      ++argc;                /// remove the first argument that is the name of the file
      SetColor(atoi(*argv)); /// set color by call this function
      ++argv;                /// remove second string form print, because it is color code
      while( *argv ){
        std::cout << *argv <<'\n';
        ++argv;
      }
      /// no need to end line
      /// std::cout<<std::endl;
      SetColor(7);
      return 0;
    }
    • Hey k-five,

      Hah, I’d never thought that anyone would ever find this useful, I’m quite happy to see that it actually helped someone! :) Oh and don’t sweat it, my native tongue ain’t English either, it’s actually German (I’m from Austria). ;)

      Ah, since you might not be from an “ASCII” country, you may wish to look at the unicode version of this (see above, it’s in the post). If you’re from some country, whose language exceeds the capabilities of standard cmd code pages / its default font, you can colorecho a lot of characters when using a proper monospace font with the unicode version. It’s also backwards compatible!

      In any case, thanks for providing your modified source code (That’s the GPL spirit ;) )! Ah, I took the freedom to edit your post to make the code look proper. Unfortunately, the weblog software doesn’t allow syntax highlighting and line numbering in comments, I hope it’s okay. ;)

      Oh, and just out of curiosity; Why did you push in \n instead of a Windows \r\n line break at the end? Cause this looks more like a UNIX line break in that case?

      • Hello Thrawn. In fact it is a good code but it is a little slowly. Well I want it work like (echo) in windows and I I modified it again. Maybe it is better that I use “C” instead of “C++”. I saw before “SFK soft source code” It has 65000 lines :) but it is very fast.
        http://stahlworks.com/dev/swiss-file-knife.html

        I am from Iran ( Kurdistan ) I have never been in university, I leaned EN language and C++ and … by self-study. I know C++ but I am not in a group of programmer or others, So I would like to improve MYSELF with these small projects, like, it that you share, THANKS A LOT.
        if you have ( or know ) some good source ( code, video, … ) about leaning C++ please tell me so that I can IMPROVE :).

        My new edition:

        #include <iostream>
        #include <windows.h>
        
        int setNewLine (const char** argv){
            if (atoi(*argv)==0){
                std::cerr<<"ERROR...\nMaybe you have forgotten /n or number(0..255), before your texts"<<std::endl;
                std::cout<<"Only correct syntax: cecho /n 10 your-text"<<std::endl;
                std::cout<<"And correct syntax: cecho 10 your-text"<<std::endl;
                return 0;
            }
             SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),atoi(*argv)); /// argv 1 == /n, removes before
            ++argv;
            while(*argv){                /// argv 3 == texts
                    while(*argv){
                        std::cout<<*argv<<' ';
                        ++argv;
                    }
                    std::cout<<std::endl;
            }
        }
        void notNewLine (const char** argv){
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),atoi(*argv)); /// argv 1 == color code
            ++argv;                      /// argv 1 == color code, removes
            while(*argv){                /// argv 2 == texts
                        std::cout<<*argv<<' ';
                        ++argv;
            }
        }
        
        int main(int argc, const char** argv) {
            ++argv;                             /// removes the name of the fine. argv 0
            ++argc;                             /// removes the first argument that is the name of the file
        
            if(!strcasecmp(*argv,"/n"))
                setNewLine(++argv);        /// argv 1 == /n, removes
            else if (atoi(*argv)==0){
                    //ReadConsoleOutputAttribute();
                std::cerr<<"ERROR...\nMaybe you have forgotten /n or number(0..255), before your texts"<<std::endl;
                std::cout<<"Only correct syntax: cecho /n 10 your-text"<<std::endl;
                std::cout<<"And correct syntax: cecho 10 your-text"<<std::endl;
            }
            else
                notNewLine(argv);
        
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
          return 0;
        }
        • Hi k-five,

          Frankly, I can’t really help you that much. I’m not a programmer myself, I’m just a dirty hacker. Yes, I’ve been to university, but only for 1 year, I failed computer science mostly because of Analysis I (abstract math..), so yeah. Working as a Linux/UNIX and a-bit-of-Windows administrator now.

          So in essence, I just grabbed some code of the web, modified it a little and recompiled it to suit my simple needs. If you can improve it, by all means, please do! It’s not really my code in the end after all. ;) I’ve been fixing a bit of C and C++ in my time (mostly for getting code to run on systems like FreeBSD, OpenBSD, Solaris or Haiku OS), but I don’t really qualify as a coder…. When it comes to actually writing solutions for problems myself, it’ll boil down to Perl most of the time…

          By the way, it’s quite interesting that you’re from Iran. We’ll get an Iranian researcher at work in October, for about 10 months. That’s new for me as well, for now we had people from Hong Kong, Malaysia (not the Muslim part), Pakistan (that was one nasty experience by the way), India, France, Colombia, Turkey and Greece. It’ll be interesting whether I can learn something about Iranian culture from that guy. There is a lot of tension right now, so let’s see how this’ll work out.

          In any case, thank you for contributing your code once more. :)

          • Hello. You are welcome.
            Okay, I hope you can be good luck in your job.
            I have learned “cmd, powershell, bash, 10-finger-type, c++, EN language, … ” and but I am beginner at all.
            Anyway, thanks a lot for spending your time to talk to me, and PLEASE correct the code that you modified.
            You put twice “( in main ( argc … ) ” above in my code, Maybe someone see it, then it thinks OH Iranian programmer use two main function in you code ;) :).

            • Hey k-five,

              My apologies! It was not my intention to mess up your code at all! All I wanted was to put it in “pre” tags to maintain indentations and give it a monospace font. But the stupid parsers of the weblog software fucked everything up (it’s not the first time either). It’ll usually mess with < , > and sometimes with the brackets, but this level of destruction is quite new. I'll drop you an email, so you can send me your correct source code via that way.

              I'll fix this, but your code is so mangled now, I can't get it right anymore without the correct sources. Sorry for that. :(

              • Hello && No problem :) && I have sent you back the code +.png of it.

                • Hi k-five!

                  Thanks, it’s fixed now! I had the weblog software updated just recently, and it seems they changed the code parsers, which is how I got everything so messed up. It’s a bit disturbing how different the blog code behaves when using the proper tags in a post and in a comment. It’s just a mess…

                  Anyhow, it should be good now! :)

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">

(required)

(required)