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
Removing colors from output
提问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 sed
command 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 sed
line 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 -r
option 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 0f
with 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:
看:
回答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