bash:在写入标准输出之前捕获并着色部分输出

bash: Capture and colorize parts of output before writing to stdout

我正在捕获变量中 command/script 的输出。输出本质上是一个文本块。在这个问题的上下文中,让我们考虑一下:

output='In java, both Errors and Exceptions are the subclasses of some/long/path/to/file.java class. Error refers to an illegal operation at line=23 and executed by app=client

问题: 我喜欢在写入 stdout 之前对部分消息进行着色。我设法找到了一种方法,但有意义/仅适用于一个替代。

color_end=$'[0m'
color_red=$'[31m'

echo "${output//line=/${color_red}LINE=$color_end}"

我也喜欢匹配和着色其他部分(比如 <filename>.javaapp=)。我尝试在上面的变量替换中使用正则表达式,但是 none 这些工作。出现语法错误或类似错误。

echo "${output//(line=|app=)/${color_red}$color_end}"

尝试使用 sed,但 1) 颜色会被解释,因此在写入标准输出时 2) 正则表达式模式有点毛茸茸。

实现此目标的最佳方法是什么?


FWIW,所有匹配的部分只有一种颜色。不同的匹配部分没有不同的颜色。

我会这样做:

# Only set colors if printing to a terminal
test -t 1 && t_red1=$'3[31m' t_01=$'3[0m'

# List here the regexes to highlight
echo "$output" |
sed -E 's/[[:alnum:]_]+=|[^[:space:]]+\.java'/"$t_red1&$t_01/g"
  • 这可以使用 BASH_REMATCH 在纯 bash 中完成,但 sed 更简单,而且可能更有效。
  • 文件路径的正则表达式在这里有效,但很脆弱 - 路径中的 space 会破坏它。
  • 但您可以使用此模板添加要突出显示的正则表达式。
  • test -t 1 确保仅当 stdout (fd 1) 是终端时才设置变量,这很重要。
  • t_red1 指的是 t 颜色 red 的终端控制序列,在文件描述符 1.
  • 我使用这种表示法是因为它在字符串中的嵌入相对较短,t_ 与其他变量区分开来,尾随的 fd 数字允许每个文件描述符有单独的控制序列(每个文件描述符可能是也可能不是一个终端)。
  • 例如,要使用彩色错误消息(在 fd2/stderr 上),您可以添加一行 test -t 2 && t_red2=$'3[31m' t_02=$'3[0m'.