Removing colors from output

倖福魔咒の 提交于 2019-11-26 05:19:10

问题


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?


回答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,2}(;[0-9]{1,2})?)?[mGK]//g"



回答2:


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.




回答3:


For Mac OSX or BSD use

./somescript | sed $'s,\x1b\\[[0-9;]*[a-zA-Z],,g'



回答4:


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"



回答5:


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)




回答6:


Hmm, not sure if this will work for you, but 'tr' will 'strip' (delete) control codes - try:

./somescript | tr -d '[:cntrl:]'



回答7:


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}" )"



回答8:


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:

  1. linuxjournal.com: Extended Globbing
  2. gnu.org: Bash Parameter Expansion



回答9:


@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)



回答10:


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



回答11:


This works for me:

./somescript | cat


来源:https://stackoverflow.com/questions/17998978/removing-colors-from-output

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!