Classificando strings com códigos de escape ANSI

4

Estou tentando imprimir uma lista classificada de todas as opções do zsh, com as opções de conjunto coloridas em verde e as opções não definidas coloridas em vermelho. Não consigo fazer com que sort funcione corretamente nas linhas coloridas. A seguir, são impressas todas as opções vermelhas seguidas por todas as opções verdes:

print -lP "%F{green}"${^$(setopt)} "%F{red}"${^$(unsetopt)} | sort

Eu percebi que isso ocorreu porque print -P está expandindo as strings de formato, de modo que cada linha de opção comece com ^[[31m para vermelho e ^[[32m para verde. Olhando para o sort manpage , vi duas opções que podem ajudar:

-i, --ignore-nonprinting consider only printable characters

-k, --key=POS1[,POS2] start a key at POS1 (origin 1), end it at POS2 (default end of line)

Então eu tentei:

print -lP "%F{green}"${^$(setopt)} "%F{red}"${^$(unsetopt)} | sort -i

e

print -lP "%F{green}"${^$(setopt)} "%F{red}"${^$(unsetopt)} | sort --key=<N>

Onde tentei definir <N> para muitos números diferentes. Em todos os casos, obtive os mesmos resultados (todas as opções vermelhas antes de todas as cores verdes). Como posso resolver isso?

    
por Sean Mackesey 27.09.2014 / 17:33

2 respostas

3

-k opção de classificação aceita dois argumentos numéricos: campo e caractere. Você quer classificar no 6º caractere do primeiro campo. É 6º caractere porque %F{green} é substituído por ESC[32m . Então, isso deve funcionar:

print -lP "%F{green}"${^$(setopt)} "%F{red}"${^$(unsetopt)} | sort -k 1.6
    
por 27.09.2014 / 18:23
3

Em uma seqüência de escape como ^[[31m , o caractere de escape ^[ não é impresso, mas os outros caracteres [31m são caracteres de impressão. Portanto, sort -i não ajudará: ignora os caracteres de escape, mas ainda classifica [31mred[0m antes de [32mgreen[0m .

Uma maneira genérica de classificar os dados de acordo com critérios que vão além das capacidades integradas do utilitário sort é dobrar os dados em cada linha, massageando-o de forma que a primeira cópia seja a chave de ordenação, classifique o linhas e, finalmente, tira a primeira parte. Por exemplo, supondo que os dados que você deseja classificar não contenham caracteres de tabulação:

awk '{s=$0; gsub(/3\[[ -?]*[@-~]/,"",s); print s "\t" $0}' |
sort |
awk 'BEGIN {RS="\t"} {print $2}'
    
por 28.09.2014 / 03:21