196

我有一些产生颜色输出的脚本,我需要删除 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

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

4

18 回答 18

206

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

(正确地,[m|K]应该是(m|K)or [mK],因为你不是想匹配一个管道字符。但这现在并不重要。)

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

./somescript | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g"
于 2013-08-01T17:13:08.113 回答
57

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

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

这是一个更简单的答案,它处理 256 色转义并适用于非 GNU 的系统sed

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

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

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

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

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

于 2018-07-02T18:26:45.643 回答
43

我无法从任何其他答案中获得体面的结果,但以下内容对我有用:

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

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

于 2017-09-17T08:23:54.900 回答
39

对于 Mac OSX 或 BSD 使用

./somescript | sed $'s,\x1b\\[[0-9;]*[a-zA-Z],,g'
于 2019-02-12T10:53:16.790 回答
29

下面的正则表达式会遗漏一些ANSI Escape Codes序列以及 3 位颜色。regex101.com 上的示例修复

改用这个:

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

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

例如,这个输入发生了:echo "$(tput setaf 1)foo$(tput sgr0) bar"

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

./somescript | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | sed "s/\x0f//g"
于 2016-02-23T16:24:51.557 回答
22

我在 Debian 的包中遇到了ansi2txt工具。colorized-logs该工具从 STDIN 中删除 ANSI 控制代码。

使用示例:

./somescript | ansi2txt

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

于 2021-04-29T11:19:27.507 回答
9

纯 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
}

看:

  1. linuxjournal.com:扩展通配符
  2. gnu.org:Bash 参数扩展
于 2019-02-19T12:15:23.203 回答
7

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

以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}

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

string_sed="$( sed -r "s/\x1B(\[[0-9;]*[JKmsu]|\(B)//g" <<< "${string}" )"
于 2018-10-12T14:02:16.133 回答
6

嗯,不确定这是否适合您,但 'tr' 将 'strip'(删除)控制代码- 尝试:

./somescript | tr -d '[:cntrl:]'
于 2014-04-03T17:31:36.647 回答
4

这是一个纯 Bash 解决方案。

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

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

重击 >= 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

重击 < 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
于 2018-03-22T09:15:06.970 回答
3

有争议的想法是为此进程环境重新配置终端设置,以让进程知道终端不支持颜色。

TERM=xterm-mono ./somescript我想到了类似的东西。YMMV 与您的特定操作系统和脚本理解终端颜色设置的能力。

于 2020-05-01T20:57:57.100 回答
3

@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)
于 2016-03-13T19:50:00.033 回答
2

还有一个处理 ANSI 转义序列的专用工具:ansifilter。使用默认--text输出格式去除所有 ANSI 转义序列(注意:不仅仅是着色)。

参考:https ://stackoverflow.com/a/6534712

于 2020-10-04T23:26:56.707 回答
2

不确定里面有什么,./somescript但如果转义序列不是硬编码的,你可以设置终端类型来避免它们

TERM=dumb ./somescript 

例如,如果您尝试

TERM=dumb tput sgr0 | xxd

你会看到它没有输出,而

tput sgr0 | xxd
00000000: 1b28 421b 5b6d                           .(B.[m

确实(对于 xterm-256color)。

于 2020-10-05T04:07:33.900 回答
0

我遇到了这个问题/答案,试图做与 OP 类似的事情。我发现了一些其他有用的资源,并基于这些资源提出了一个日志脚本。在这里发帖以防它可以帮助其他人。

挖掘链接有助于理解一些我不会尝试解释的重定向,因为我自己才刚刚开始理解它。

使用会将彩色输出呈现到控制台,同时从进入日志文件的文本中去除颜色代码。它还将在日志文件中包含任何不起作用的命令的 stderr。

编辑:在底部添加更多用法以显示如何以不同方式登录

#!/bin/bash
set -e
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

. $DIR/dev.conf
. $DIR/colors.cfg

filename=$(basename ${BASH_SOURCE[0]})
# remove extension
# filename=`echo $filename | grep -oP '.*?(?=\.)'`
filename=`echo $filename | awk -F\. '{print $1}'`
log=$DIR/logs/$filename-$target

if [ -f $log ]; then
  cp $log "$log.bak"
fi

exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>$log 2>&1


# log message
log(){
    local m="$@"
    echo -e "*** ${m} ***" >&3
    echo "=================================================================================" >&3
  local r="$@"
    echo "================================================================================="
    echo -e "*** $r ***" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g"
    echo "================================================================================="
}

echo "=================================================================================" >&3
log "${Cyan}The ${Yellow}${COMPOSE_PROJECT_NAME} ${filename} ${Cyan}script has been executed${NC}"
log $(ls) #log $(<command>)

log "${Green}Apply tag to image $source with version $version${NC}"
# log $(exec docker tag $source $target 3>&2) #prints error only to console
# log $(docker tag $source $target 2>&1) #prints error to both but doesn't exit on fail
log $(docker tag $source $target 2>&1) && exit $? #prints error to both AND exits on fail
# docker tag $source $target 2>&1 | tee $log # prints gibberish to log
echo $? # prints 0 because log function was successful
log "${Purple}Push $target to acr${NC}"


以下是其他有帮助的链接:

于 2020-08-22T16:37:09.310 回答
0

我的贡献:

./somescript | sed -r "s/\\x1B[\\x5d\[]([0-9]{1,3}(;[0-9]{1,3})?(;[0-9]{1,3})?)?[mGK]?//g"
于 2022-01-10T14:24:54.620 回答
0

我使用 perl,因为我必须经常对许多文件执行此操作。这将遍历所有文件名*.txt 的文件,并删除任何格式。这适用于我的用例,也可能对其他人有用,所以只想在这里发布。替换您的文件名代替 filename*.txt 或者您可以在设置下面的 FILENAME 变量时将文件名用空格分隔。

$ FILENAME=$(ls filename*.txt) ; for file in $(echo $FILENAME); do echo $file; cat $file | perl -pe 's/\e([^\[\]]|\[.*?[a-zA-Z]|\].*?\a)//g' | col -b > $file-new; mv $file-new $file; done
于 2020-12-16T14:48:33.443 回答
-7

这对我有用:

./somescript | cat
于 2017-07-25T23:48:13.527 回答