bash tee去除颜色

时间:2012-01-04 00:13:31

标签: bash exec logging tee

我目前正在使用以下内容捕获发送到终端的所有内容并将其放入日志文件

exec 4<&1 5<&2 1>&2>&>(tee -a $LOG_FILE)

但是,我不希望颜色转义码/杂乱进入日志文件。所以我有类似的东西,有点工作

exec 4<&1 5<&2 1>&2>&>(
    while read -u 0; do
        #to terminal
        echo "$REPLY"
        #to log file (color removed)
        echo "$REPLY" | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' >> $LOG_FILE
    done
    unset REPLY #tidy
)

除了read等待回车,这对于脚本的某些部分来说并不理想(例如echo -n "..."printf没有\n)。


Jonathan Leffler回答的后续行动:

给出示例脚本test.sh

#!/bin/bash

LOG_FILE="./test.log"
echo -n >$LOG_FILE

exec 4<&1 5<&2 1>&2>&>(tee -a >(sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' > $LOG_FILE))


##### ##### #####
# Main

echo "starting execution"
printf "\n\n"

echo "color test:"
echo -e "\033[0;31mhello \033[0;32mworld\033[0m!"
printf "\n\n"

echo -e "\033[0;36mEnvironment:\033[0m\n  foo: cat\n  bar: dog\n  your wife: hot\n  fix: A/C"
echo -n "Before we get started. Is the above information correct?  "
read YES
echo -e "\n[READ] $YES" >> $LOG_FILE
YES=$(echo "$YES" | sed 's/^\s*//;s/\s*$//')
test ! "$(echo "$YES" | grep -iE '^y(es)?$')" && echo -e "\nExiting... :(" && exit
printf "\n\n"

#...some hundreds of lines of code later...

echo "Done!"


##### ##### #####
# End

exec 1<&4 4>&- 2<&5 5>&-

echo "Log File: $LOG_FILE"
  1. 到终端的输出是预期的,并且日志文件中没有所需的颜色转义码/杂乱。但是,在检查test.log后,我看不到[READ] ...(请参阅test.sh的第21行)。

  2. [我的实际bash脚本]的日志文件在结束时包含行Log File: ...,即使在关闭4和5 fds之后也是如此。我能够通过在第二个sleep 1之前放置一个exec来解决这个问题 - 我认为有一个竞争条件或fd shenanigans应该归咎于它。不幸的是,对于你们,我无法用test.sh重现这个问题,但我对任何人可能有的猜测感兴趣。

6 个答案:

答案 0 :(得分:3)

考虑使用Is it possible to distribute stdin over parallel processes中讨论的pee计划。它允许您通过sed脚本发送日志数据,同时继续将颜色发送到实际输出。

这样做的一个主要优点是它会删除每行日志输出'执行sed一次';这对于绩效来说真的是恶魔般的(就执行的流程数而言,如果没有别的话)。

答案 1 :(得分:1)

我知道这不是一个完美的解决方案,但cat -v会将像\x1B这样的非可见字符转换为^[[1;34m这样的可见形式。输出将是混乱的,但至少它将是ascii文本。

答案 2 :(得分:1)

我通过在运行命令之前设置TERM=dumb来做这样的事情。除了tab,CR和LF之外,它几乎删除了任何控制字符。我不知道这是否适用于您的情况,但值得一试。问题是你不会在终端上看到颜色编码,因为它是一个哑终端。

您还可以尝试使用viscat(尤其是-v参数),看看这些是否适合您。你只需将它们放在你的管道中就像这样:

exec 4<&1 5<&2 1>&2>&>(tee -a | cat -v | $LOG_FILE)

顺便说一句,几乎所有终端程序都有一个选项来捕获输入,并且大多数都是为你清理它。您使用的是什么平台,以及您使用的是什么类型的终端程序?

答案 3 :(得分:0)

您可以尝试使用-n选项进行读取。它读取n个字符而不是等待新行。你可以把它设置为一个。这将增加代码运行的迭代次数,但不会等待换行。

来自男人:

-n NCHARS read returns after reading NCHARS characters rather than waiting for a complete line of input.

注意:我没有测试过这个

答案 4 :(得分:0)

您可以使用ANSIFilter来剥离或转换带有ANSI转义序列的控制台输出。

请参阅http://www.andre-simon.de/zip/download.html#ansifilter

答案 5 :(得分:0)

可能不是screen -Lscript命令是可行选项而不是此exec循环吗?