【问题标题】:bash tee remove colorbash tee 去除颜色
【发布时间】:2012-01-04 00:13:30
【问题描述】:

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

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 之后也是如此。我可以通过在第二个exec 之前放置一个sleep 1 来解决这个问题——我认为这应该归咎于竞争条件或fd 恶作剧。对你们来说不幸的是,我无法使用 test.sh 重现此问题,但我会对任何人的猜测感兴趣。

【问题讨论】:

  • 请注意,\e[...m 代码特定于 VT100/VT200/等。并且可能不是程序在不同类型的 $TERM 上实际输出的那些。

标签: bash exec logging tee


【解决方案1】:

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

这样做的一个主要优点是它将删除“每行日志输出执行一次sed”;这对于性能来说真的很糟糕(就执行的进程数量而言,如果没有别的)。

【讨论】:

  • 太棒了!谢谢你! exec 4&lt;&amp;1 5&lt;&amp;2 1&gt;&amp;2&gt;&amp;&gt;(tee -a &gt;(sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' &gt; $LOG_FILE))
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    您也可以尝试viscat(尤其是-v 参数),看看它们是否对您有用。您只需像这样将它们放入您的管道中:

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

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

    【讨论】:

      【解决方案4】:

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

      来自男人:

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

      注意:我没有测试过这个

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

          screen -Lscript 命令可能不是这个 exec 循环的可行选项吗?

          【讨论】:

          • 我们可以用screen关闭控制字符吗?
          猜你喜欢
          • 1970-01-01
          • 2011-09-19
          • 2019-03-13
          • 2020-04-11
          • 2014-09-08
          • 2019-02-15
          • 2011-03-19
          • 1970-01-01
          • 2012-03-21
          相关资源
          最近更新 更多