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

#!/bin/bash

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

./somescript

输出为(在日志文件中):

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

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

我把剧本改成:

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

但是现在它给了我(在日志文件中):

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

我怎么也可以删除这个'@[60G?

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


当前回答

这是一个纯Bash解决方案。

保存为strip-escape-codes.sh,使其可执行,然后执行<command- production - colour -output> | ./strip-escape-codes.sh。

注意,这将删除所有的ANSI转义码/序列。如果你只想去除颜色,用“m”替换[a-zA-Z]。

Bash >= 4.0:

#!/usr/bin/env bash

# Strip ANSI escape codes/sequences [$1: input string, $2: target variable]
function strip_escape_codes() {
    local _input="$1" _i _char _escape=0
    local -n _output="$2"; _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:

#!/usr/bin/env bash

# Strip ANSI escape codes/sequences [$1: input string, $2: 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 "$2=\"${output}\""                       # assign output to target variable
}

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

其他回答

我无法从其他答案中得到满意的结果,但下面的答案对我来说很有用:

somescript | sed -r "s/[[:cntrl:]]\[[0-9]{1,3}m//g"

如果我只删除了控制字符“^[”,它就会留下其余的颜色数据,例如“33m”。加上颜色代码和“m”就成功了。我对s/\x1B//g不工作感到困惑,因为\x1B[31m当然可以与echo一起工作。

Mac OSX或BSD使用

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

我在Debian的有色日志包中遇到了ansi2txt工具。该工具删除来自STDIN的ANSI控制代码。

使用的例子:

./somescript | ansi2txt

源代码http://github.com/kilobyte/colorized-logs

我有一些彩色输出的问题,其他解决方案在这里没有正确处理,所以我建立了这个perl一行。它查找转义\e,后面跟着开括号\[,后面跟着1或颜色代码\d+,以分号分隔,以m结尾。

perl -ple 's/\e\[\d+(;\d+)*m//g'

对于彩色编译器输出,它似乎工作得非常好。

根据维基百科的说法,您正在使用的sed命令中的[m|K]是专门用于处理m(颜色命令)和K(“擦除行部分”命令)的。您的脚本试图将光标的绝对位置设置为60 (^[[60G),以获得一行中的所有ok,这是sed行没有覆盖的。

正确地,[m|K]应该是(m|K)或[mK],因为您并没有试图匹配一个管道字符。但现在这并不重要。)

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

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