Uma ferramenta de shell para “tablify” dados de entrada contendo códigos de escape ANSI

3

Eu tenho entrada contendo códigos de cores ANSI que gostaria de tablificar. Eu quero que a saída permaneça colorida, então a saída tablificada deve manter os códigos de cores ANSI. Por isso, ingenuamente removê-los não atende aos meus requisitos.

Por exemplo, para esta entrada,

3[0;32;1mgreen_apple3[0m 1 100
orange 20 19
pineapple 1000 87
avocado 4 30

A saída que eu esperava seria semelhante a

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

Na saída acima, "green_apple" deve ser colorido de acordo com os códigos de cores da entrada, ou seja, verde. Eu gostaria de saber como isso pode ser feito.

Eu tentei coluna, mas não lida com códigos ANSI. A saída de

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

infelizmente

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

Observe a não tabulação.

    
por Jimmy Dean 24.03.2014 / 08:56

5 respostas

2

Eu não acho que haja tal comando, você teria que fazer à mão. Algo como:

awk '
  {
    nf[NR]=NF
    for (i = 1; i <= NF; i++) {
      f[NR,i] = $i
      gsub(/3\[[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]]
    }
  }'
    
por 24.03.2014 / 13:02
1

O problema é claro, com column não diferenciando entre caracteres de impressão e não-impressão, bash contorna isso em seu prompt ( PS1 ) com seu recurso de escape \[ \] , não sei qualquer outra coisa que faça exatamente isso.

Eu tentei um hack rápido e desagradável, já que o seu campo problemático está no início da linha, mova-o para o fim , mas você se depara com problemas de preenchimento / alinhamento que não são facilmente resolvidos usando utilitários comuns.

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

Se você tiver a instalação do módulo perl HTML::FromANSI , ela tem um script ansi2html útil:

ls -l --color | ansi2html -f

Isso só leva você para o meio do caminho, agora você precisa alinhar a saída HTML ...

Existe uma solução simples (embora leve e pesada) com HTML como intermediário: o layout das tabelas HTML é efetivamente o que você está tentando fazer.

Isso usa ansifilter do Andre Simon , por exemplo:

ls -l --color | ansifilter -fH

Isso converte seqüências ANSI em HTML ( <span style="..."></span> ), então isso pode ser descartado usando um navegador com capacidade de texto em modo ANSI como elinks .

Se o HTML incompleto for um problema, você pode executar hxclean ou htmltidy para limpar o HTML antes de passá-lo para um navegador.

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

Você deve ser capaz de usar elinks ou w3m para isso

O script table.pl se divide no espaço em branco e adiciona as tags relevantes da tabela HTML para obter a formatação desejada:

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

Não apenas se divide em nenhum espaço em branco, ele se divide em espaço em branco que não está dentro de '<' '>' colchetes angulares para que não quebre a tag <span> . Essa não é uma boa maneira de analisar HTML, mas deve ser suficiente para o tipo de entrada restrita aqui.

Você pode precisar (eu fiz) para definir ou substituir as cores padrão, ou adicioná-las ao seu arquivo ~/.elinks/elinks.conf :

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

Certifique-se de usar os elinks mais recentes (0.12.x), versões anteriores não suportam saída de cores ANSI.

    
por 25.03.2014 / 12:08
1

Para qualquer pessoa interessada, adaptei este script awk da resposta de Stéphane Chazelas . Você deve ser capaz de soltá-lo em seu $PATH e executá-lo na linha de comando.

Por exemplo:

> 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(/3\[([[: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]]
    }
}
    
por 07.06.2018 / 19:02
0

Algum sed work faria o truque:

  • a sed para remover códigos de cores ANSI

    sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g"
    
  • a sed para substituir o (s) espaço (s) por guias

    sed -r "s/\s+/\t/g"
    

Finaly:

printf "3[0;32;1mgreen_apple3[0m 1 100
orange 20 19
pineapple 1000 87
avocado 4 30" \
| sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" \
| sed -r "s/\s+/\t/g"

Saída:

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

PS : Eu honestamente testei tudo isso com ls --color output . Isso é mais fácil do que brincar com o eco.

Sobre a remoção de códigos de cores ANSI:

por 24.03.2014 / 09:15
0

Supondo que os nomes das frutas contenham apenas _ e alphabetic caracteres.

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

Saída:

3[0;32;1mgreen_apple3[0m  1     100
orange       20    19
pineapple    1000  87
avocado      4     30

Para (teste) exibir a saída em cores, apenas printf o pipeline via substituição do comando shell , por exemplo:

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

Saída com cor - somente green_apple mostra em cores.

green_apple  1     100
orange       20    19
pineapple    1000  87
avocado      4     30
    
por 01.06.2015 / 05:16