用于“表格化”包含 ANSI 转义码的输入数据的 shell 工具

用于“表格化”包含 ANSI 转义码的输入数据的 shell 工具

我的输入包含我想要表格化的 ANSI 颜色代码。我希望输出保持彩色,因此表格输出应保持 ANSI 颜色代码。因此,天真地剥离它们并不符合我的要求。

例如,对于此输入,

\033[0;32;1mgreen_apple\033[0m 1 100
orange 20 19
pineapple 1000 87
avocado 4 30

我期望的输出类似于

green_apple 1    100
orange      20   19
pineapple   1000 87
avocado     4    30

在上面的输出中,“green_apple”应根据输入的颜色代码(即绿色)进行着色。我想知道如何实现这一点。

我已经尝试过列,但它不处理 ANSI 代码。的输出

echo '\033[0;32;1mgreen_apple\033[0m 1 100
orange 20 19
pineapple 1000 87
avocado 4 30' | column -t

不幸的是

green_apple  1     100
orange                  20    19
pineapple               1000  87
avocado                 4     30

注意非表格化。

答案1

我认为没有这样的命令,你必须手动执行。就像是:

awk '
  {
    nf[NR]=NF
    for (i = 1; i <= NF; i++) {
      f[NR,i] = $i
      gsub(/\033\[[0-9;]*[mK]/, "", $i)
      len[NR,i] = l = length($i)
      if (l > max[i]) max[i] = l
    }
  }
  END {
    for (n = 1; n <= NR; n++) {
      for (i = 1; i < nf[n]; i++)
        printf "%s%*s", f[n,i], max[i]+1-len[n,i], ""
      print f[n,nf[n]]
    }
  }'

答案2

对于任何感兴趣的人,我改编了这个 awk 脚本斯特凡·查泽拉斯的回答。您应该能够将其放入您的计算机中$PATH并从命令行运行它。

例如:

> echo -e '\e[32mHello\e[0m,World\nFoo,Bar' | colorcolumn FS=',' OFS=' | '
Hello | World
Foo   | Bar
#!/usr/bin/awk -f
#
# colorcolumn - Like `column`, but works with ANSI colors
#
# Based on this Stack Exchange answer by Stephane Chazelas:
#     https://unix.stackexchange.com/a/121139/259233

{
    nf[NR]=NF
    for (i = 1; i <= NF; i++) {
        cell[NR,i] = $i
        gsub(/\033\[([[:digit:]]+(;[[:digit:]]+)*)?[mK]/, "", $i)
        len[NR,i] = l = length($i)
        if (l > max[i]) max[i] = l
    }
}
END {
    for (row = 1; row <= NR; row++) {
        for (col = 1; col < nf[row]; col++)
            printf "%s%*s%s", cell[row,col], max[col]-len[row,col], "", OFS
        print cell[row,nf[row]]
    }
}

答案3

问题当然是column不区分打印和非打印字符,通过其提示符 ( ) 及其转义功能bash来解决这个问题,我不知道还有什么其他方法可以做到这一点。PS1\[ \]

鉴于您的问题领域位于开始该行的,将其移至 then结尾,但是您会遇到类似的填充/对齐问题,而使用常见实用程序无法轻松解决这些问题。

ls -l --color | rev | column -t  | rev   # not a useful solution

如果你安装了 perlHTML::FromANSI模块,它有一个有用的ansi2html脚本:

ls -l --color | ansi2html -f

这只能让你成功一半,现在你必须对齐 HTML 输出......

有一个简单的(虽然稍微重量级的)解决方案,以 HTML 作为中间:HTML 表格的布局实际上就是您想要做的事情。

这使用安德烈·西蒙抗过滤器,例如:

ls -l --color | ansifilter -fH

这会将 ANSI 序列转换为 HTML ( <span style="..."></span>),然后可以使用支持文本模式 ANSI 的浏览器(例如电子链接

如果 HTML 不完整是个问题,您可以选择运行hxclean或者htmltidy在将 HTML 传递到浏览器之前清理它。

ls -l --color  | ansifilter -fH | perl table.pl | elinks -dump -dump-color-mode 1 

你应该能够使用电子链接或者w3m 为了这

table.pl脚本按空格分割并添加相关的 HTML 表标签以实现所需的格式:

print "<table>\n";
while (<>) { 
    print "<tr><td>" . 
      join("</td><td>", split(/((?!<[^>]+)\s+(?![^<]+>))/) ) . 
      "</td></tr>\n"; 
}
print "</table>\n";

事实并非如此只是在任何空格上分割,它会在不在“<”“>”尖括号内的空格上分割,因此不会破坏标签<span>。这不是解析 HTML 的好方法,但对于此处的约束输入类型来说应该足够了。

您可能需要(我确实)设置或覆盖默认颜色,或者将它们添加到您的~/.elinks/elinks.conf文件中:

set document.colors.use_document_colors = 1
set document.colors.text = "#000000"
set document.colors.background = "#ffffff"

确保使用最新的 (0.12.x) elinks,早期版本不支持 ANSI 颜色输出。

答案4

假设水果名称仅包含_alphabetic字符。

c='(\e|\\033)\[[0-9;]+m'
sed -r "s/^($c)?([a-zA-Z_]+)($c)?/& \3/" file | column -t | 
sed -r "s/^($c[a-zA-Z_]+$c)( +)([a-zA-Z_]+)/\5\4\1/" |
sed -r "s/^[^ ]+ +//"

输出:

\033[0;32;1mgreen_apple\033[0m  1     100
orange       20    19
pineapple    1000  87
avocado      4     30

要(测试)以颜色显示输出,printf只需管道通过shell命令替换,例如:

c='(\e|\\033)\[[0-9;]+m'; printf "$(
sed -r "s/^($c)?([a-zA-Z_]+)($c)?/& \3/;" file | column -t | 
sed -r "s/^($c[a-zA-Z_]+$c)( +)([a-zA-Z_]+)/\5\4\1/" |
sed -r "s/^[^ ]+ +//" )"

带颜色输出 –仅有的 青苹果以颜色显示。

green_apple  1     100
orange       20    19
pineapple    1000  87
avocado      4     30

相关内容