Bash - Converte texto colorido de caractere de escape para BBCode

4

Eu quero converter um texto terminal escape-character colored text file para BBCode colored. Para isso, criei um arquivo de log do Android com logcat -Cd > /sdcard/logcat.txt . A opção -C adiciona os caracteres de escape de cor. A saída é assim:

[0m[38;5;231mV/Zygote  ( 4666): Switching descriptor 55 to /dev/null
[0m[38;5;231mV/Zygote  ( 4666): Switching descriptor 9 to /dev/null
[0m[38;5;40mI/ggheart ( 1111): onStop
[0m[38;5;40mI/Test    ( 1111): onStop
[0m[38;5;75mD/ActivityThread( 4666): handleBindApplication:com.mxtech.videoplayer.ad
[0m[38;5;75mD/ActivityThread( 4666): setTargetHeapUtilization:0.75
[0m[38;5;75mD/ActivityThread( 4666): setTargetHeapMinFree:2097152

Para converter os códigos de cores para BBCode , escrevi este script sed :

#!/bin/bash
#Use 'logcat -Cd > /sdcard/logcat.txt' as input file

sed '/\x1b/ {
    s/\x1b\[0m\x1b\[38;5;40m/\[COLOR="Green"\]/
    s/\x1b\[0m\x1b\[38;5;196m/\[COLOR="Red"\]/
    s/\x1b\[0m\x1b\[38;5;75m/\[COLOR="Blue"\]/
    s/\x1b\[0m\x1b\[38;5;166m/\[COLOR="Sienna"\]/
    s/\x1b\[0m\x1b\[38;5;231m/\[COLOR="DarkSlateGray"\]/
    s/\x1b\[38;5;40m/\[COLOR="Green"\]/
    s/\x1b\[38;5;196m/\[COLOR="Red"\]/
    s/\x1b\[38;5;75m/\[COLOR="Blue"\]/
    s/\x1b\[38;5;166m/\[COLOR="Sienna"\]/
    s/\x1b\[38;5;231m/\[COLOR="DarkSlateGray"\]/
    s/\x1b\[0m/\[COLOR="Black"\]/
    s/$/\[\/COLOR\]/
    }' <logcat.txt >logcat2.txt

O texto da saída processada é semelhante a este:

[COLOR="DarkSlateGray"]V/Zygote  ( 4666): Switching descriptor 55 to /dev/null[/COLOR]
[COLOR="DarkSlateGray"]V/Zygote  ( 4666): Switching descriptor 9 to /dev/null[/COLOR]
[COLOR="Green"]I/ggheart ( 1111): onStop[/COLOR]
[COLOR="Green"]I/Test    ( 1111): onStop[/COLOR]
[COLOR="Blue"]D/ActivityThread( 4666): handleBindApplication:com.mxtech.videoplayer.ad[/COLOR]
[COLOR="Blue"]D/ActivityThread( 4666): setTargetHeapUtilization:0.75[/COLOR]
[COLOR="Blue"]D/ActivityThread( 4666): setTargetHeapMinFree:2097152[/COLOR]

Isso é sintaticamente correto e funciona corretamente em fóruns correspondentes, mas não é otimizado e desperdiça muitos caracteres (que são limitados na maioria das placas) devido a COLOR de tags que não ultrapassam várias linhas.

Deverá ter esta aparência onde as mesmas linhas coloridas não fecham / reabrem a mesma tag COLOR :

[COLOR="DarkSlateGray"]V/Zygote  ( 4666): Switching descriptor 55 to /dev/null
V/Zygote  ( 4666): Switching descriptor 9 to /dev/null[/COLOR]
[COLOR="Green"]I/ggheart ( 1111): onStop
I/Test    ( 1111): onStop[/COLOR]
[COLOR="Blue"]D/ActivityThread( 4666): handleBindApplication:com.mxtech.videoplayer.ad
D/ActivityThread( 4666): setTargetHeapUtilization:0.75
D/ActivityThread( 4666): setTargetHeapMinFree:2097152[/COLOR]

Alguma ideia de como conseguir isso? É possível até mesmo com processador de texto baseado em linha? Não é obrigatório contanto que seja executado em shell / bash / cygwin.

    
por Maniaxx 07.02.2015 / 20:04

2 respostas

1

Observando um comentário sobre "Fácil usando o awk", isso seria relativo ao sed.

OP descrevia um recurso não muito bem documentado de logcat (consulte commit ) que informa logcat para atribuir cores codificadas a cada linha com base na prioridade da entrada de log.

Existem outras opções, como logcat-color , PID cat e coloredlogcat que permite colorir diferentes campos , por exemplo, aumentando a possibilidade de várias cores por linha.

Aqui está um script awk que reconhece as cores do logcat codificado, mas permite várias cores por linha:

#!/usr/bin/awk -f
BEGIN {
        colors["0"]        = "Black";
        colors["38;5;40"]  = "Green";
        colors["38;5;196"] = "Red";
        colors["38;5;75"]  = "Blue";
        colors["38;5;166"] = "Sienna";
        colors["38;5;231"] = "DarkSlateGray";
        color = "";
        last = "";
        this = "";
        save = "";
}
/3/ {
        done = "";
        while ( $0 ~ /3\[[;0-9]*m/ ) {
                mark = match($0, /3\[[;0-9]*m/ );
                if ( mark > 1 ) { done = done substr($0, 1, mark - 1); }
                item = substr($0, RSTART + 2, RLENGTH - 3);
                $0 = substr($0, RSTART + RLENGTH);
                if ( match($0, /^3\[[;0-9]*m/ ) > 0 ) continue;
                color = colors[item];
                if ( done == "" ) this = color;
                if ( item == "0" ) color = "";
                if ( color == "" ) {
                        if ( $0 != "" ) last = color;
                        $0 = "[/COLOR]" $0;
                } else if (color != last) {
                        $0 = "[COLOR=\"" color "\"]" $0;
                        last = color;
                }
        }
        $0 = done $0;
        if ( last != "" ) $0 = $0 "[/COLOR]";
}
{
        if ( NR > 1 ) {
                if ( this == last) sub("\[/COLOR\]$", "", save);
                print save;
        }
        save = $0;
}
END {
        if ( NR > 0 ) print save;
}

Com o exemplo original:

^[[0m^[[38;5;231mV/Zygote  ( 4666): Switching descriptor 55 to /dev/null
^[[0m^[[38;5;231mV/Zygote  ( 4666): Switching descriptor 9 to /dev/null
^[[0m^[[38;5;40mI/ggheart ( 1111): onStop
^[[0m^[[38;5;40mI/Test    ( 1111): onStop
^[[0m^[[38;5;75mD/ActivityThread( 4666): handleBindApplication:com.mxtech.videoplayer.ad
^[[0m^[[38;5;75mD/ActivityThread( 4666): setTargetHeapUtilization:0.75
^[[0m^[[38;5;75mD/ActivityThread( 4666): setTargetHeapMinFree:2097152

você receberia a saída solicitada:

[COLOR="DarkSlateGray"]V/Zygote  ( 4666): Switching descriptor 55 to /dev/null
V/Zygote  ( 4666): Switching descriptor 9 to /dev/null
[COLOR="Green"]I/ggheart ( 1111): onStop
I/Test    ( 1111): onStop
[COLOR="Blue"]D/ActivityThread( 4666): handleBindApplication:com.mxtech.videoplayer.ad
D/ActivityThread( 4666): setTargetHeapUtilization:0.75
D/ActivityThread( 4666): setTargetHeapMinFree:2097152[/COLOR]

mas alterando a entrada para

^[[0m^[[38;5;231mV/Zygote  ( 4666): Switching descriptor 55 to /dev/null
^[[0m^[[38;5;231mV/Zygote  ( 4666): Switching descriptor 9 to /dev/null
^[[0m^[[38;5;40mI/ggheart ( ^[[38;5;75mI/ggheart 1111^[[0m): onStop
^[[0m^[[38;5;40mI/Test    ( 1111): onStop
^[[0m^[[38;5;75mD/ActivityThread( 4666): handleBindApplication:com.mxtech.videoplayer.ad
^[[0m^[[38;5;75mD/ActivityThread( 4666): setTargetHeapUtilization:0.75
^[[0m^[[38;5;75mD/ActivityThread( 4666): setTargetHeapMinFree:2097152

fornece este resultado:

[COLOR="DarkSlateGray"]V/Zygote  ( 4666): Switching descriptor 55 to /dev/null
V/Zygote  ( 4666): Switching descriptor 9 to /dev/null[/COLOR]
[COLOR="Green"]I/ggheart ( [COLOR="Blue"]I/ggheart 1111[/COLOR]): onStop
[COLOR="Green"]I/Test    ( 1111): onStop
[COLOR="Blue"]D/ActivityThread( 4666): handleBindApplication:com.mxtech.videoplayer.ad
D/ActivityThread( 4666): setTargetHeapUtilization:0.75
D/ActivityThread( 4666): setTargetHeapMinFree:2097152[/COLOR]
    
por 18.12.2016 / 22:15
1

Parece mais fácil com perl :

perl -0777 -pe '
  BEGIN{
    %c = (
      "38;5;40" => "Green",
      "38;5;196" => "Red",
      "38;5;75" => "Blue",
      "38;5;166" => "Sienna",
      "38;5;231" => "DarkSlateGray",
      "38;5;40" => "Green",
      "38;5;196" => "Red",
      "38;5;75" => "Blue",
      "38;5;166" => "Sienna",
      "38;5;231" => "DarkSlateGray",
      "0" => "Black");
    $esc = qr{\e\[([\d;]*)m};
  }

  s{$esc(.*?)(?=$|$esc)}{
    $ret = $2;
    if ($2 ne "" && $1 ne $last) {
      $ret = (defined($last) && "[/COLOR]") . "[COLOR=\"$c{$1}\"]$2";
      $last = $1
    }
    $ret
  }gse;

  s{$}{[/COLOR]} if $last'

(aqui tomando a abordagem preguiçosa e carregando o arquivo inteiro na memória.

    
por 18.12.2016 / 23:52