我有一些脚本,产生输出的颜色,我需要删除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?
也许有一种方法可以完全禁用整个脚本的着色?
根据维基百科的说法,您正在使用的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"
下面的正则表达式将错过一些ANSI转义码序列,以及3位颜色。regex101.com的示例和修复。
用这个代替:
./somescript | sed -r 's/\x1B\[(;?[0-9]{1,3})+[mGK]//g'
我也有问题,有时,SI字符出现。
例如,输入echo "$(tput setaf 1)foo$(tput sgr0) bar"
这里有一种方法也可以剥离SI字符(shift in) (0x0f)
./somescript | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | sed "s/\x0f//g"
@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)
这是一个纯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
恕我直言,大多数答案都过于努力地限制转义代码中的内容。结果,它们最终会丢失常见的代码,如[38;5;60m(前景色ANSI颜色60来自256色模式)。
它们还需要启用GNU扩展的-r选项。这些都不是必需的;它们只是让正则表达式读起来更好。
下面是一个更简单的答案,它处理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)
我也遇到过类似的问题。我发现的所有解决方案都适用于颜色代码,但没有删除“$(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}
为了正常工作,regex必须扩展以匹配由sgr0 ("\E(B"))添加的序列:
string_sed="$( sed -r "s/\x1B(\[[0-9;]*[JKmsu]|\(B)//g" <<< "${string}" )"
我遇到了这个问题/答案,试图做一些类似于op的事情。我找到了一些其他有用的资源,并在此基础上提出了一个日志脚本。在这里发帖,希望能帮助到其他人。
深入研究这些链接有助于理解一些重定向,我不会尝试解释,因为我自己也刚刚开始理解它。
Usage会将彩色输出呈现到控制台,同时将颜色代码从文本中剥离到日志文件。它还将在日志文件中包含任何无效命令的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}"
以下是其他有用的链接:
我可以使用sed操作一个变量在bash?
https://www.cyberciti.biz/faq/redirecting-stderr-to-stdout/
https://unix.stackexchange.com/questions/42728/what-does-31-12-23-do-in-a-script
https://serverfault.com/questions/103501/how-can-i-fully-log-all-bash-scripts-actions
https://www.gnu.org/software/bash/manual/bash.html#Redirections