Parsing linux color control sequences

I'm trying to render the output of a linux shell command in HTML. For example, systemctl status mysql looks like this in my terminal:

enter image description here

As I understand from Floz'z Misc I was expecting that the underlying character stream would contain control codes. But looking at it in say hexyl (systemctl status mysql | hexyl) I can't see any codes:

enter image description here

Looking near the bottom on lines 080 and 090 where the text "Active: failed" is displayed, I was hoping to find some control sequences to change the color to red. While not necessarily ascii, I used some ascii tables to help me:

  • looking at the second lot of 8 characters on line 090 where the letters ive: fa are displayed, I find:
  • 69 = i
  • 76 = v
  • 65 = e
  • 3a = :
  • 20 = space
  • 66 = f
  • 61 = a
  • 69 = i

There are no bytes for control sequences.

I wondered if hexyl is choosing not to display them so I wrote a Java program which outputs the raw bytes after executing the process as a bash script and the results are the same - no control sequences.

The Java is roughly:

p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "systemctl status mysql"}); // runs in the shell
p.waitFor();
byte[] bytes = p.getInputStream().readAllBytes();
for(byte b : bytes) {
    System.out.println(b + "\t" + ((char)b));
}

That outputs:

...
32   
32   
32   
32   
32   
65  A
99  c
116 t
105 i
118 v
101 e
58  :
32   
102 f
97  a
105 i
108 l
101 e
100 d
...

So the question is: How does bash know that it has to display the word "failed" red?


Solution 1:

systemctl detects that the output is not a terminal, and it removes colors codes from the output.

Related: Detect if stdin is a terminal or pipe? , https://unix.stackexchange.com/questions/249723/how-to-trick-a-command-into-thinking-its-output-is-going-to-a-terminal , https://superuser.com/questions/1042175/how-do-i-get-systemctl-to-print-in-color-when-being-interacted-with-from-a-non-t

Tools sometimes (sometimes not) come with options to enable color codes always, like ls --color=always, grep --color=always on in case of systemd with SYSTEMD_COLORS environment variable.


What tool can I use to see them?

You can use hexyl to see them.

how does bash know that it has to mark the word "failed" red?

Bash is the shell, it is completely unrelated.

Your terminal, the graphical window that you are viewing the output with, knows to mark it red because of ANSI escape sequences in the output. There is no interaction with Bash.


$ SYSTEMD_COLORS=1 systemctl status dbus.service | grep runn | hexdump -C
00000000  20 20 20 20 20 41 63 74  69 76 65 3a 20 1b 5b 30  |     Active: .[0|
00000010  3b 31 3b 33 32 6d 61 63  74 69 76 65 20 28 72 75  |;1;32mactive (ru|
00000020  6e 6e 69 6e 67 29 1b 5b  30 6d 20 73 69 6e 63 65  |nning).[0m since|
00000030  20 53 61 74 20 32 30 32  32 2d 30 31 2d 30 38 20  | Sat 2022-01-08 |
00000040  31 39 3a 35 37 3a 32 35  20 43 45 54 3b 20 35 20  |19:57:25 CET; 5 |
00000050  64 61 79 73 20 61 67 6f  0a                       |days ago.|
00000059