Bash 从输出中删除颜色
我有一些脚本可以生成带有颜色的输出,我需要删除ANSI代码Bash 从输出中删除颜色,bash,unix,colors,console,ansi-escape,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 输出为(在日志文件中): 我不知道如何将ESC字符放在这里,所以我将@放在它的位置 我将脚本更改为: #!/bin/bash exec > >(tee log) # red
#!/bin/bash
exec > >(tee log) # redirect the output to a file but keep it on stdout
exec 2>&1
./somescript
输出为(在日志文件中):
我不知道如何将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"
但现在它给了我(在日志文件中):
如何删除此“@[60G
”
也许有一种方法可以完全禁用整个脚本的着色功能?,您正在使用的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"
嗯,不确定这是否适用于您,但'tr'将'strip'(删除)控制代码-尝试:
./somescript | tr -d '[:cntrl:]'
下面的正则表达式将丢失一些序列,以及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)的方法
@杰夫·鲍曼的解决方案帮助我摆脱了一些色码。 我在正则表达式中添加了另一小部分,以便删除更多:
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)
这对我很有用:
./somescript | cat
我无法从其他任何一个答案中得到令人满意的结果,但以下几点对我很有用:
somescript | sed -r "s/[[:cntrl:]]\[[0-9]{1,3}m//g"
如果我只删除了控制字符“^[”,它会留下其余的颜色数据,例如“33m”。包括颜色代码和“m”就完成了这项任务。我对s/\x1B//g不起作用感到困惑,因为\x1B[31m肯定与echo一起工作。这里有一个纯Bash解决方案 另存为
strip escape codes.sh
,使其可执行,然后运行|。/strip escape codes.sh
请注意,这将剥离所有ANSI转义码/序列。如果只想剥离颜色,请将[a-zA-Z]
替换为“m”
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
!/usr/bin/env bash
#带ANSI转义码/序列[$1:输入字符串,$2:目标变量]
功能条\转义\代码(){
本地输入=“$1”\u i\u字符\u转义=0
本地-n_output=“$2”_output=“”
对于(_i=0;_i<${#u input};_i++),请执行以下操作
_char=“${u输入:{u i:1}”
如果(${u escape}==1));那么
如果[[“${{u char}”==[a-zA-Z]];那么
_逃逸=0
fi
持续
fi
如果[[“${u char}”==$'\e']];则
_逃逸=1
持续
fi
_输出+=“${u char}”
完成
}
当读取-r行时;执行
strip_转义码“${line}”行
回显“${line_}”
完成
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
!/usr/bin/env bash
#带ANSI转义码/序列[$1:输入字符串,$2:目标变量]
功能条\转义\代码(){
本地输入=“${1/\”/\\\“}”输出=“”i char escape=0
对于((i=0;i<${#input};++i)),do#处理输入字符串的所有字符
char=“${input:i:1}”#从输入字符串中获取当前字符
如果(${escape}==1));那么#如果我们当前在一个转义序列中,请检查
如果[[“${char}”==[a-zA-Z]];则到达#结尾,即如果当前字符是字母
逃逸=0#到达终点,我们不再处于逃逸序列中
fi
继续#跳过当前字符,即不添加到输出
fi
如果[[“${char}”==$'\e']];那么#如果当前字符是'\e',我们已经到达开始位置
转义=转义序列的1#->设置标志
继续#跳过当前字符,即不添加到输出
fi
输出+=“${char}”#将当前字符添加到输出
完成
eval“$2=\”${output}\”\将输出分配给目标变量
}
当读取-r行时;执行
strip_转义码“${line}”行
回显“${line_}”
完成
IMHO,这些答案中的大多数都试图限制转义码内的内容。因此,它们最终会丢失常见代码,如[38;5;60m
(256色模式下的前景ANSI颜色60)
它们还需要启用的-r
选项。这些选项不是必需的;它们只是使正则表达式的可读性更好
下面是一个更简单的答案,用于处理256色转义,并适用于具有非GNUsed
的系统:
./somescript | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g'
这将捕获以[
开头、有任意数量的小数和分号、以字母结尾的任何内容。这将捕获以下任何内容
对于趣味,这里有一个更大、更通用(但测试最少)的解决方案:
/somescript | sed's/\x1B[@A-Z\\\]^\x1B\[[0-9:;?]*[-!“\$%&'””()*+,.\/]*[\@A-Z^ A-Z{A-Z}]///g'
(如果您有@edi9999的SI问题,请在末尾添加
|sed“s/\x0f//g”
;这可以通过将0f
替换为不需要的字符的十六进制来实现)我也有类似的问题。我找到的所有解决方案都适用于颜色代码,但没有删除“$(tput sgr0)”添加的字符。
(重置属性)
例如,下面示例中结果字符串的长度是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}
适用于Mac OSX或BS
#!/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 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g'
./somescript | sed 's/\x1B[@A-Z\\\]^_]\|\x1B\[[0-9:;<=>?]*[-!"#$%&'"'"'()*+,.\/]*[][\\@A-Z^_`a-z{|}~]//g'
#!/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}
string_sed="$( sed -r "s/\x1B(\[[0-9;]*[JKmsu]|\(B)//g" <<< "${string}" )"
./somescript | sed $'s,\x1b\\[[0-9;]*[a-zA-Z],,g'
# 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
}
TERM=dumb ./somescript
TERM=dumb tput sgr0 | xxd
tput sgr0 | xxd
00000000: 1b28 421b 5b6d .(B.[m
./somescript | ansi2txt