从输出中删除颜色

时间:2013-08-01 15:59:09

标签: bash unix colors console ansi-escape

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

也许有办法完全禁用整个脚本的着色?

17 个答案:

答案 0 :(得分:118)

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

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

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

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

答案 1 :(得分:20)

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

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

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

答案 2 :(得分:11)

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

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

答案 3 :(得分:10)

对于Mac OSX或BSD使用

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

答案 4 :(得分:9)

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

他们还需要启用GNU extensions-r选项。这些不是必需的。他们只是使正则表达式的阅读效果更好。

这是处理256色转义符并在非GNU sed的系统上工作的简单答案:

./somescript | sed 's/\x1B\[[0-9;]\+[A-Za-z]//g'

这将捕获以[开头,具有任意数量的小数和分号以及以字母结尾的所有内容。这应该捕获任何common ANSI escape sequences

对于趣味性,这是针对all conceivable ANSI escape sequences的更大,更通用(但未经测试)的解决方案:

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

(如果您有@ edi9999的SI问题,请在末尾添加| sed "s/\x0f//g";将0f替换为不需要的char的十六进制,对于any control char来说是有效的)

答案 5 :(得分:8)

我也遇到了问题,有时候会出现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"

答案 6 :(得分:4)

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

例如,在下面的示例中,comment by 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}" )"

答案 7 :(得分: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)

答案 8 :(得分:3)

纯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: Extended Globbing
  2. gnu.org: Bash Parameter Expansion

答案 9 :(得分:3)

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

我想到TERM=xterm-mono ./somescript之类的东西。具有特定操作系统的YMMV以及脚本了解终端颜色设置的功能。

答案 10 :(得分:3)

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

用法示例:

./somescript | ansi2txt

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

答案 11 :(得分:1)

如果需要在强大的> Bash脚本中执行此操作,可以使用以下函数:

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

这是一个匹配原始问题用例的示例。保存为example.sh,然后运行<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

答案 12 :(得分:1)

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

ref:https://stackoverflow.com/a/6534712

答案 13 :(得分: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}"


以下其他链接也有帮助:

答案 14 :(得分:0)

不确定./somescript中的内容,但是如果未对转义序列进行硬编码,则可以设置终端类型来避免它们

TERM=dumb ./somescript 

例如,如果您尝试

TERM=dumb tput sgr0 | xxd

您会看到它在一段时间内不产生任何输出

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

(对于xterm-256color)。

答案 15 :(得分:0)

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

$ FILENAME = $(ls文件名* .txt);用于$(echo $ FILENAME)中的文件;回显$ file;猫$文件| perl -pe's / \ e([^ []] | [。?[a-zA-Z] |]。?\ a)// g'| col -b> $ file-new; mv $ file-new $ file;完成

答案 16 :(得分:-5)

这对我有用:

./somescript | cat