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?
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,2}(;[0-9]{1,2})?)?[mGK]//g"
I couldn't get decent results from any of the other answers, but the following worked for me:
somescript | sed -r "s/[[:cntrl:]]\[[0-9]{1,3}m//g"
If I only removed the control char "^[", it left the rest of the color data, e.g., "33m". Including the color code and "m" did the trick. I'm puzzled with s/\x1B//g doesn't work because \x1B[31m certainly works with echo.
For Mac OSX or BSD use
./somescript | sed $'s,\x1b\\[[0-9;]*[a-zA-Z],,g'
I also had the problem that sometimes, the SI character appeared .
It happened for example with this input : echo "$(tput setaf 1)foo$(tput sgr0) bar"
Here's a way to also strip the SI character (shift in) (0x0f)
./somescript | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | sed "s/\x0f//g"
Hmm, not sure if this will work for you, but 'tr' will 'strip' (delete) control codes - try:
./somescript | tr -d '[:cntrl:]'
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;]\+[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 untested) 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)
I had a similar problem. All solutions I found did work well for the color codes but did not remove the characters added by "$(tput sgr0)"
(resetting attributes).
Taking, for example, the solution in the comment by davemyron the length of the resulting string in the example below is 9, not 6:
#!/usr/bin/env bash
string="$(tput setaf 9)foobar$(tput sgr0)"
string_sed="$( sed -r "s/\x1B\[[0-9;]*[JKmsu]//g" <<< "${string}" )"
echo ${#string_sed}
In order to work properly, the regex had to be extend to also match the sequence added by sgr0
("\E(B
"):
string_sed="$( sed -r "s/\x1B(\[[0-9;]*[JKmsu]|\(B)//g" <<< "${string}" )"
@jeff-bowman's solution helped me getting rid of SOME of the color codes. I added another small portion to the regex in order to remove some more:
sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" # Original. Removed Red ([31;40m[1m[error][0m)
sed -r "s/\x1B\[([0-9];)?([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" # With an addition, removed yellow and green ([1;33;40m[1m[warning][0m and [1;32;40m[1m[ok][0m)
^^^^^^^^^
remove Yellow and Green (and maybe more colors)
Much simpler function in pure Bash to filter-out common ANSI codes from a text stream:
# Strips common ANSI codes from a text stream
shopt -s extglob # Enable Bash Extended Globbing expressions
ansi_filter() {
local line
local IFS=
while read -r line || [[ "$line" ]]; do
echo "${line//$'\e'[\[(]*([0-9;])[@-n]/}"
done
}
See:
If one needs to do this within a Bash script, the following function may be used:
# Strip escape codes/sequences [$1: input, $2: target variable]
function strip_escape_codes() {
local input="${1//\"/\\\"}" output="" i char within_code=0
for ((i=0; i < ${#input}; ++i)); do
char="${input:i:1}" # get current character
if (( ${within_code} == 1 )); then # if we're currently within an escape code, check if end of
case "${char}" in # code is reached, i.e. if current character is a letter
[a-zA-Z]) within_code=0 ;; # we're no longer within an escape code
esac
continue
fi
if [[ "${char}" == $'\e' ]]; then # if current character is '\e', we've reached an escape code
within_code=1 # now we're within an escape code
continue
fi
output+="${char}" # if none of the above applies, add current character to output
done
eval "$2=\"${output}\"" # assign output to target variable
}
Here's an example matching the use case of the original question. Save as example.sh
and then run <command-producing-colored-output> | example.sh
:
#!/bin/bash
# copy&paste function strip_escape_codes here
while read -r line; do
strip_escape_codes "${line}" stripped
echo "${stripped}"
done
This works for me:
./somescript | cat
来源:https://stackoverflow.com/questions/17998978/removing-colors-from-output