Problema ao escolher uma chave de classificação para um arquivo de texto

1

Suponha que eu tenha um arquivo de texto como este:

e8:b4:c8:b2:d8:b9                       "Biswas Gautam"                   2016            me            Mob
ec:8e:b5:f8:a2:12                       "Dipin Gyawali"                   2015            me            Lan
f0:27:65:70:91:62                       "Karan Rai"                       2016            cs            Mob
f0:de:f1:33:33:32                       "Dipendra L. Karki"               2015            me            Lan

Eu quero classificá-lo pela terceira coluna (anos) e pela quarta coluna com lote como eu (engenharia mecânica) & cs (ciência da computação) & terceiro pelo nome

Mas o nome da segunda coluna está criando problema; às vezes eles têm um nome do meio, o que entra em conflito com a minha solução inicial. Então eu pensei que as aspas duplas podem resolver o problema. Mas eu não tenho idéia de como ignorar o espaço entre aspas duplas.

sort -k 4 -k 5 -k 2 -kfilename

Eu escrevi 4 porque haverá três espaços, um devido à coluna e um devido ao nome completo (Nome [espaço] Sobrenome)

Existe alguma maneira de classificar essas coisas?

    
por aftershock 23.02.2018 / 17:40

4 respostas

0
$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | sed 's/@/    /g'
ec:8e:b5:f8:a2:12    "Dipin Gyawali"    2015    me    Lan
f0:de:f1:33:33:32    "Dipendra Karki"    2015    me    Lan
e8:b4:c8:b2:d8:b9    "Biswas Gautam"    2016    me    Mob
f0:27:65:70:91:62    "Karan Rai"    2016    cs    Mob

Isso substitui qualquer execução de três ou mais espaços com o caractere @ (qualquer caractere que não esteja presente nos dados funcionará).

Em seguida, sort é instruído a interpretar sua entrada como campos @ -delimited e classifica no terceiro campo (ano) e no quinto campo (dispositivo). O% final sed substitui cada @ nos dados classificados por quatro espaços (você pode optar por inserir uma guia literal aqui ou \t com o GNU sed ).

Mais bonito:

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | column -s @ -t
ec:8e:b5:f8:a2:12  "Dipin Gyawali"   2015  me  Lan
f0:de:f1:33:33:32  "Dipendra Karki"  2015  me  Lan
e8:b4:c8:b2:d8:b9  "Biswas Gautam"   2016  me  Mob
f0:27:65:70:91:62  "Karan Rai"       2016  cs  Mob

Os seguintes usos usam awk para formatar cada coluna como uma cadeia de 20 caracteres justificada à esquerda:

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | awk -F@ '{ for (i=1;i<=NF;++i) printf("%-20s",$i); print "" }'
ec:8e:b5:f8:a2:12   "Dipin Gyawali"     2015                me                  Lan
f0:de:f1:33:33:32   "Dipendra Karki"    2015                me                  Lan
e8:b4:c8:b2:d8:b9   "Biswas a Gautam"   2016                me                  Mob
f0:27:65:70:91:62   "Karan Rai"         2016                cs                  Mob

Ou você pode formatá-los individualmente:

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | awk -F@ '{ printf("%s %-30s %-30s %-30s %s\n", $1,$2,$3,$4,$5) }'
ec:8e:b5:f8:a2:12 "Dipin Gyawali"                2015                           me                             Lan
f0:de:f1:33:33:32 "Dipendra Karki"               2015                           me                             Lan
e8:b4:c8:b2:d8:b9 "Biswas a Gautam"              2016                           me                             Mob
f0:27:65:70:91:62 "Karan Rai"                    2016                           cs                             Mob
    
por 23.02.2018 / 17:51
0

Se o seu arquivo estiver estritamente formatado (como exibido), você poderá solicitar que sort use colunas específicas para as chaves:

sort -k1.75,1.78n -k1.91,1.92 -k1.105,1.107 -k1.41,1.74 input

... que transforma a entrada de amostra em:

f0:de:f1:33:33:32                       "Dipendra Karki"                  2015            me            Lan
ec:8e:b5:f8:a2:12                       "Dipin Gyawali"                   2015            me            Lan
f0:27:65:70:91:62                       "Karan Rai"                       2016            cs            Mob
e8:b4:c8:b2:d8:b9                       "Biswas Gautam"                   2016            me            Mob
    
por 23.02.2018 / 18:10
0

Se você quiser preservar o espaçamento exatamente (em vez de reformatá-lo, como em resposta de Kusalananda ) e não não quer depender das posições exatas da coluna (como em resposta de Jeff Schaller ), algo como este script Perl trabalho:

#!/usr/bin/perl
use 5.022;

my @dat;
while (<<>>) {
    #          0     1      2        3     4     5     6     7     8
    #          mac   sp     name     sp    yr    sp    dpt   sp    net
    my @m = /^(\S+) (\s+) "([^"]+)" (\s+) (\S+) (\s+) (\S+) (\s+) (\S+)$/x
        or die "invalid line: $_";
    push @dat, \@m;
}

@dat = sort {
    $a->[4] <=> $b->[4] || $a->[6] cmp $b->[6] || $a->[2] cmp $b->[2]
} @dat;

foreach (@dat) {
    print join('', @$_), "\n";
}

Observe que usa o Perl v5.22.0 ou posterior para o operador <<>> ; ele deve funcionar com versões antigas do Perl se você usar <> . O programa tem essencialmente três "parágrafos": o primeiro analisa suas linhas usando um regexp, também capturando o espaçamento exato usado. O segundo parágrafo classifica os dados. O terceiro parágrafo imprime de volta.

    
por 23.02.2018 / 18:51
0

Outra abordagem seria substituir cada caractere de espaço entre entre aspas pelo caractere de espaço reservado @, fazer a classificação e, em seguida, alterar os caracteres @ de volta para espaços:

perl -pe 's#("[^"]*")#$1 =~ s/ /@/rg#eg' filename | sort -k 3 -k 4 -k 2 | sed 's/@/ /g'
    
por 23.02.2018 / 19:03

Tags