Como ordenar o arquivo por ocorrência de caractere por linha?

3

Sou bastante novo no Linux e encontrei muitas informações úteis sobre como fazer contagens de caracteres em um arquivo, mas existe uma maneira no Linux / terminal de classificar um arquivo de texto pelo número de vezes que um caractere específico ocorre por linha?

Por exemplo dado:

baseball
aardvark
a man a plan a canal panama
cat
bat
bill

Classifique pelo número de ocorrências da letra "a" cedendo:

a man a plan a canal panama
aardvark
baseball
cat
bat
bill

Em relação a "gato" e "morcego" em uma ocorrência de "a" cada, não me interessa se a ordem das linhas com contagens iguais se inverte, apenas interessada em um tipo geral de linhas por frequência de caracteres.

    
por incognito1138 01.08.2015 / 22:09

5 respostas

5

A abordagem geral com esse tipo de tarefa é usar awk ou perl ... para calcular a métrica em que você está interessado e pré-anexá-la à linha. Em seguida, alimente-a com sort e remova a métrica da saída classificada:

awk '{print gsub("a","a"), $0}' < file | sort -rn | cut -d' ' -f2-
    
por 01.08.2015 / 22:55
3

Outra transformação Schwartziana:

$ awk -Fa '{print NF,$0}' file | sort -nr | cut -d' ' -f2-
a man a plan a canal panama
aardvark
baseball
cat
bat
bill

Ou, em Perl:

perl -Fa -lane 'print "$#F $_"' file | sort -nr | cut -d' ' -f2-
    
por 02.08.2015 / 10:01
3

Você também pode classificar o caractere:

tr -cd a\n <file | paste - ./file | LC_ALL=C sort -rk1,1 | cut -f2-

Veja como fica seu exemplo depois de ser tr anslated e paste d antes de ser canalizado para sort :

aa  baseball
aaa aardvark
aaaaaaaaaa  a man a plan a canal panama
a   cat
a   bat
    bill

Em seguida, sort obtém e, todas as coisas sendo iguais, classifica as chaves mais curtas antes das chaves mais longas, mas em -r everse, e sua saída é ...

aaaaaaaaaa  a man a plan a canal panama
aaa aardvark
aa  baseball
a   cat
a   bat
    bill

... e cut simplesmente desaparecem na primeira guia.

a man a plan a canal panama
aardvark
baseball
cat
bat
bill
    
por 02.08.2015 / 08:47
0
#!/bin/bash
cat input.txt |
while IFS= read -r a; do
    b=${a//[^a]}
    echo "${#b} $a"
done | sort -rn | sed 's/[^ ]* //'
    
por 01.08.2015 / 22:29
0

Desde que a transformação Schwartziana foi mencionada, estou surpreso em ver que ninguém ainda postou uma implementação Perl pura de uma:

perl -ne 'push @a, $_ }{ print map { $_->[0] } sort { $b->[1] <=> $a->[1] } map { [$_, $_ =~ tr/a//] } @a' file
a man a plan a canal panama
aardvark
baseball
cat
bat
bill

Cada linha do arquivo é enviada para @a , depois que o arquivo for lido, a contagem do caractere a é usada para classificar a matriz.

Como contar o número de ocorrências de um caractere não é uma função tão cara para computar, um método mais conciso seria apenas usar a classificação por si só:

$ perl -ne 'push @a, $_ }{ print sort { $b =~ tr/a// <=> $a =~ tr/a// } @a' file
a man a plan a canal panama
aardvark
baseball
cat
bat
bill
    
por 02.08.2015 / 13:12