I have some script that produces output with colors and I need to remove the ANSI codes.

#!/bin/bash

exec > >(tee log)   # redirect the output to a file but keep it on stdout
exec 2>&1

./somescript

The output is (in log file):

java (pid  12321) is running...@[60G[@[0;32m  OK  @[0;39m]

I didn't know how to put the ESC character here, so I put @ in its place.

I changed the script into:

#!/bin/bash

exec > >(tee log)   # redirect the output to a file but keep it on stdout
exec 2>&1

./somescript | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g"

But now it gives me (in log file):

java (pid  12321) is running...@[60G[  OK  ]

How can I also remove this '@[60G?

Maybe there is a way to completely disable coloring for the entire script?


Solution 1:

According to Wikipedia, the [m|K] in the sed command you're using is specifically designed to handle m (the color command) and K (the "erase part of line" command). Your script is trying to set absolute cursor position to 60 (^[[60G) to get all the OKs in a line, which your sed line doesn't cover.

(Properly, [m|K] should probably be (m|K) or [mK], because you're not trying to match a pipe character. But that's not important right now.)

If you switch that final match in your command to [mGK] or (m|G|K), you should be able to catch that extra control sequence.

./somescript | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g"

Solution 2:

IMHO, most of these answers try too hard to restrict what is inside the escape code. As a result, they end up missing common codes like [38;5;60m (foreground ANSI color 60 from 256-color mode).

They also require the -r option which enables GNU extensions. These are not required; they just make the regex read better.

Here is a simpler answer that handles the 256-color escapes and works on systems with non-GNU sed:

./somescript | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g'

This will catch anything that starts with [, has any number of decimals and semicolons, and ends with a letter. This should catch any of the common ANSI escape sequences.

For funsies, here's a larger and more general (but minimally tested) solution for all conceivable ANSI escape sequences:

./somescript | sed 's/\x1B[@A-Z\\\]^_]\|\x1B\[[0-9:;<=>?]*[-!"#$%&'"'"'()*+,.\/]*[][\\@A-Z^_`a-z{|}~]//g'

(and if you have @edi9999's SI problem, add | sed "s/\x0f//g" to the end; this works for any control char by replacing 0f with the hex of the undesired char)