Bash Tee 命令去除颜色

14

我目前正在使用以下代码来捕获所有传输到终端的内容并将其记录到日志文件中

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
)

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


回应 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脚本的日志文件在关闭4和5个fds后仍包含Log File: ...这一行。我通过在第二个exec之前放置sleep 1来解决了这个问题 - 我认为这可能是由于竞争条件或fd操作导致的。不幸的是,我无法通过test.sh重现这个问题,但我会对任何人的猜测感兴趣。


请注意,\e[...m 代码是特定于 VT100/VT200 等终端的,可能不是在不同类型的 $TERM 上实际输出的代码。 - jørgensen
6个回答

6
考虑使用在是否可能将标准输入分布到并行进程中讨论的pee程序。 这将允许您通过sed脚本发送日志数据,同时继续将颜色发送到实际输出。
其中一个主要优点是它会消除“每行日志输出执行一次sed”的问题;这对性能非常不利(至少从执行的进程数量来看)。

2
太好了!谢谢!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)) - Andrew Sohn

3

我知道这不是一个完美的解决方案,但是cat -v命令会把像\x1B这样的不可见字符转换为可见形式,例如^[[1;34m。输出结果可能会很混乱,但至少它是ASCII文本。


1

我曾经通过在运行命令之前设置TERM=dumb来执行此类操作。这基本上除了制表符、回车和换行符之外,删除了任何控制字符。我不知道这是否适用于您的情况,但值得一试。问题是,由于它是一个愚蠢的终端,您也看不到终端上的颜色编码。

您还可以尝试使用viscat(特别是-v参数),看看它们是否对您有所帮助。您只需将它们放入管道中,如下所示:

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

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


0
您可以尝试使用 read 命令的 -n 选项。该选项会读取 n 个字符,而不是等待一个新行。您可以将其设置为 1。这将增加代码运行的迭代次数,但它不会等待新行。
来自 man 手册:
“-n NCHARS read 命令在读取 NCHARS 个字符后返回,而不是等待完整的输入行。”
注意:我没有测试过这个功能。

0

0

这个执行循环,screen -Lscript 命令是否可能是替代选项?


我们能否使用 screen 关闭控制字符? - Stuart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接