bash 从输出中去除颜色

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17998978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 23:59:50  来源:igfitidea点击:

Removing colors from output

bashunixcolorsconsoleansi-escape

提问by Pawel P.

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

我有一些脚本可以生成带有颜色的输出,我需要删除 ANSI 代码。

#!/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.

我不知道如何把 ESC 字符放在这里,所以我把@它放在这里。

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?

我怎样才能删除这个 ' @[60G

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

也许有一种方法可以完全禁用整个脚本的着色?

回答by Jeff Bowman

According to Wikipedia, the [m|K]in the sedcommand 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 sedline doesn't cover.

根据 Wikipedia,您正在使用[m|K]sed命令中的 专门用于处理m(颜色命令)和K(“擦除行的一部分”命令)。您的脚本试图将绝对光标位置设置为 60 ( ^[[60G) 以获取一行中的所有 OK,而您的sed行未涵盖该行。

(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.)

(正确地,[m|K]应该可能是(m|K)or [mK],因为您不是在尝试匹配管道字符。但这现在并不重要。)

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.

如果您将命令中的最终匹配切换为[mGK](m|G|K),您应该能够捕获该额外的控制序列。

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

回答by JoeAndrieu

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.

如果我只删除控制字符“^[”,它会留下其余的颜色数据,例如“33m”。包括颜色代码和“m”就行了。我对 s/\x1B//g 不工作感到困惑,因为 \x1B[31m 肯定适用于回声。

回答by grebulon

For Mac OSX or BSD use

对于 Mac OSX 或 BSD 使用

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

回答by meustrus

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

恕我直言,这些答案中的大多数都试图限制转义代码中的内容。结果,它们最终丢失了常见代码,例如[38;5;60m(来自 256 色模式的前景 ANSI 颜色 60)。

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

他们还需要-r启用GNU 扩展的选项。这些不是必需的;他们只是让正则表达式读得更好。

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

这是一个更简单的答案,它处理 256 色转义并适用于非 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.

这将捕获以 开头[、具有任意数量的小数和分号并以字母结尾的任何内容。这应该能捕获任何常见的 ANSI 转义序列

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

对于有趣的人,这里有一个更大、更通用(但测试最少)的解决方案,适用于所有可能的 ANSI 转义序列

./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 charby replacing 0fwith the hex of the undesired char)

(如果您有@edi9999 的 SI 问题,请添加| sed "s/\x0f//g"到末尾;通过替换为不需要的字符的十六进制,这适用于任何控制0f字符)

回答by edi9999

I also had the problem that sometimes, the SI character appeared .

我也遇到了问题,有时会出现 SI 字符。

It happened for example with this input : echo "$(tput setaf 1)foo$(tput sgr0) bar"

例如,它发生在以下输入中: echo "$(tput setaf 1)foo$(tput sgr0) bar"

Here's a way to also strip the SI character (shift in) (0x0f)

这是一种也可以去除 SI 字符(移入)(0x0f)的方法

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

回答by Dale_Reagan

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

嗯,不确定这是否适合你,但“tr”会“剥离”(删除)控制代码- 尝试:

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

回答by Jarodiv

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

我有一个类似的问题。我发现的所有解决方案都对颜色代码运行良好,但没有删除"$(tput sgr0)"(重置属性)添加的字符。

Taking, for example, the solution in the comment by davemyronthe length of the resulting string in the example below is 9, not 6:

davemyron 评论中的解决方案为例,下例中结果字符串的长度是 9,而不是 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"):

为了正常工作,必须扩展正则表达式以匹配由sgr0(" \E(B")添加的序列:

string_sed="$( sed -r "s/\x1B(\[[0-9;]*[JKmsu]|\(B)//g" <<< "${string}" )"

回答by Léa Gris

Much simpler function in pure Bash to filter-out common ANSI codes from a text stream:

纯 Bash 中更简单的函数,用于从文本流中过滤掉常见的 ANSI 代码:

# 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
  1. linuxjournal.com:扩展通配符
  2. gnu.org:Bash 参数扩展

回答by zstolar

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

@jeff-bowman 的解决方案帮助我摆脱了一些颜色代码。我在正则表达式中添加了另一小部分以删除更多内容:

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)

回答by Maxxim

Here's a pure Bash solution.

这是一个纯 Bash 解决方案。

Save as strip-escape-codes.sh, make executable and then run <command-producing-colorful-output> | ./strip-escape-codes.sh.

另存为strip-escape-codes.sh,使可执行文件,然后运行<command-producing-colorful-output> | ./strip-escape-codes.sh

Note that this strips allANSI escape codes/sequences. If you want to strip colors only, replace [a-zA-Z]with "m".

请注意,这会删除所有ANSI 转义码/序列。如果您只想去除颜色,请替换[a-zA-Z]"m"

Bash >= 4.0:

重击> = 4.0:

#!/usr/bin/env bash

# Strip ANSI escape codes/sequences [: input string, : target variable]
function strip_escape_codes() {
    local _input="" _i _char _escape=0
    local -n _output=""; _output=""
    for (( _i=0; _i < ${#_input}; _i++ )); do
        _char="${_input:_i:1}"
        if (( ${_escape} == 1 )); then
            if [[ "${_char}" == [a-zA-Z] ]]; then
                _escape=0
            fi
            continue
        fi
        if [[ "${_char}" == $'\e' ]]; then
            _escape=1
            continue
        fi
        _output+="${_char}"
    done
}

while read -r line; do
    strip_escape_codes "${line}" line_stripped
    echo "${line_stripped}"
done

Bash < 4.0:

Bash < 4.0:

#!/usr/bin/env bash

# Strip ANSI escape codes/sequences [: input string, : target variable]
function strip_escape_codes() {
    local input="${1//\"/\\"}" output="" i char escape=0
    for (( i=0; i < ${#input}; ++i )); do         # process all characters of input string
        char="${input:i:1}"                       # get current character from input string
        if (( ${escape} == 1 )); then             # if we're currently within an escape sequence, check if
            if [[ "${char}" == [a-zA-Z] ]]; then  # end is reached, i.e. if current character is a letter
                escape=0                          # end reached, we're no longer within an escape sequence
            fi
            continue                              # skip current character, i.e. do not add to ouput
        fi
        if [[ "${char}" == $'\e' ]]; then         # if current character is '\e', we've reached the start
            escape=1                              # of an escape sequence -> set flag
            continue                              # skip current character, i.e. do not add to ouput
        fi
        output+="${char}"                         # add current character to output
    done
    eval "=\"${output}\""                       # assign output to target variable
}

while read -r line; do
    strip_escape_codes "${line}" line_stripped
    echo "${line_stripped}"
done