Como classifico na primeira coluna a cada 4 linhas em um arquivo com uma chave na segunda coluna

4

Exemplo de arquivo:

A primeira coluna pode ter conjunto fixo de 4 valores não ordenados world1.com,world2.com,world3.com or world4.com

segunda coluna é uma chave que pertence a cada linha, de tal forma que cada um dos quatro conjuntos possui uma chave aleatória única.

world4.com           /randomkeyhghgdh778/key67567
world1.com           /randomkeygahjuh572/key639839
world2.com           /randomkey788gauh72/key63whjk
world3.com           /randomkey788gauh72/key63whjk
world1.com           /randomkeyhueh34778/key67uuu77
world4.com           /randomkey8998382/key6hh77686
world3.com           /randomkey7HHHH0000/key6333355k
world2.com           /randomkeyJJJJ1111/key63333

e assim por diante

Saída desejada:

world1.com           /randomkeygahjuh572/key639839
world2.com           /randomkey788gauh72/key63whjk
world3.com           /randomkey788gauh72/key63whjk
world4.com           /randomkeyhghgdh778/key67567
world1.com           /randomkeyhueh34778/key67uuu77
world2.com           /randomkeyJJJJ1111/key63333
world3.com           /randomkey7HHHH0000/key6333355k
world4.com           /randomkey8998382/key6hh77686
    
por munish 04.05.2016 / 07:05

5 respostas

5

Para organizar os arquivos pelo mundo:

$ paste -d'\n' <(grep world1 file) <(grep world2 file) <(grep world3 file) <(grep world4 file)
world1.com           /randomkeygahjuh572/key639839
world2.com           /randomkey788gauh72/key63whjk
world3.com           /randomkey788gauh72/key63whjk
world4.com           /randomkeyhghgdh778/key67567
world1.com           /randomkeyhueh34778/key67uuu77
world2.com           /randomkeyJJJJ1111/key63333
world3.com           /randomkey7HHHH0000/key6333355k
world4.com           /randomkey8998382/key6hh77686

Como funciona

Podemos usar grep para selecionar as linhas de cada mundo:

$ grep world4 file
world4.com           /randomkeyhghgdh778/key67567
world4.com           /randomkey8998382/key6hh77686

paste combina linhas de vários arquivos. O comando colar poderia ter esta aparência:

paste -d'\n' file1 file2 file3 file3.

Na verdade, não precisamos criar arquivos verdadeiros para cada mundo. Em vez disso, podemos criar objetos semelhantes a arquivos para cada um usando substituição de processo :

paste -d'\n' <(grep world1 file) <(grep world2 file) <(grep world3 file) <(grep world4 file)

A substituição do processo é suportada pelo bash, zsh e AT & ksh88 e ksh93, mas não para o traço, pdksh ou mksh.

Recurso extra: classificação por chave

Para ilustrar a flexibilidade dessa abordagem, classificaremos as chaves de cada mundo. Nota: a classificação divide os conjuntos de linhas. Não use isso se quiser manter os conjuntos juntos.

Podemos separar os mundos usando grep e, em seguida, sort cada um e, em seguida, mesclar as linhas novamente usando paste :

$ paste -d'\n' <(grep world1 file | sort -k2,2) <(grep world2 file | sort -k2,2) <(grep world3 file | sort -k2,2) <(grep world4 file | sort -k2,2)
world1.com           /randomkeygahjuh572/key639839
world2.com           /randomkey788gauh72/key63whjk
world3.com           /randomkey788gauh72/key63whjk
world4.com           /randomkey8998382/key6hh77686
world1.com           /randomkeyhueh34778/key67uuu77
world2.com           /randomkeyJJJJ1111/key63333
world3.com           /randomkey7HHHH0000/key6333355k
world4.com           /randomkeyhghgdh778/key67567

Observe que sort depende da localidade. Diferentes locales podem resultar em pedidos diferentes.

    
por 04.05.2016 / 07:40
1
#!/usr/bin/perl
use strict;
use warnings;

use autodie;
use open qw< :encoding(ASCII) >;

my $filename = $ARGV[0];
my ($ip_fh, $op_fh);
open($ip_fh, "<", $filename);
open($op_fh, ">", "$filename".".sorted");
my @ip_lines = <$ip_fh>;

for(my $i = 0; $i <= $#ip_lines; $i++)
{
    print $op_fh sort @ip_lines[$i..($i+3)];
    $i += 3;
}

close($ip_fh);
close($op_fh);

nome do arquivo de entrada como argumento da linha de comando, ex:

./sort_blocks.pl data.txt
    
por 04.05.2016 / 07:48
1

Este script perl deve funcionar com qualquer número de domínios (primeiros campos) com qualquer número de chaves (segundos campos) por domínio. Os domínios podem ter o mesmo número de chaves cada, mas não precisam.

Ele cria um hash ( %domains ) com cada elemento do hash contendo uma matriz de chaves. Ao fazer isso, ele registra o maior número de chaves visto em qualquer um dos domínios.

Depois de ler toda a entrada, ela imprime cada chave que existe para cada domínio.

#! /usr/bin/perl

use strict;
use warnings;

my %domains = ();
my $numkeys = 0;

while(<>) {
  chomp;
  my ($domain, $key) = split;
  push @{ $domains{$domain} }, $key;

  # find the largest number of keys for any domain
  $numkeys = scalar @{ $domains{$domain} } if (scalar @{ $domains{$domain} } gt $numkeys);
}

for my $keynum (0..$numkeys-1){
    foreach my $domain (sort keys %domains) {
        print "$domain\t$domains{$domain}[$keynum]\n" if (defined($domains{$domain}[$keynum]));
    }
}

Saída:

world1.com  /randomkeygahjuh572/key639839
world2.com  /randomkey788gauh72/key63whjk
world3.com  /randomkey788gauh72/key63whjk
world4.com  /randomkeyhghgdh778/key67567
world1.com  /randomkeyhueh34778/key67uuu77
world2.com  /randomkeyJJJJ1111/key63333
world3.com  /randomkey7HHHH0000/key6333355k
world4.com  /randomkey8998382/key6hh77686

Se não for considerado o mesmo número de chaves como um erro, substitua a linha print "$domain\..... no último bloco de código por:

if (defined($domains{$domain}[$keynum])) {
    print "$domain\t$domains{$domain}[$keynum]\n"
} else {
    warn "$domain is missing a key\n";
};

substitua warn por die se você quiser que seja um erro fatal.

    
por 04.05.2016 / 07:44
1
$ awk '{l=l+1; ln[$1]=$0; if (l%4==0) { \
       printf ("%s\n%s\n%s\n%s\n", ln["world1.com"], ln["world2.com"], ln["world3.com"], ln["world4.com"]); \
       delete ln; l=0; } } ' test.txt 
world1.com           /randomkeygahjuh572/key639839
world2.com           /randomkey788gauh72/key63whjk
world3.com           /randomkey788gauh72/key63whjk
world4.com           /randomkeyhghgdh778/key67567
world1.com           /randomkeyhueh34778/key67uuu77
world2.com           /randomkeyJJJJ1111/key63333
world3.com           /randomkey7HHHH0000/key6333355k
world4.com           /randomkey8998382/key6hh77686
    
por 04.05.2016 / 08:25
0

No sistema GNU:

$ NL='
'
$ <file xargs -n4 -d "$NL" sh -c 'printf "%s\n" "$@" | sort' sh
world1.com           /randomkeygahjuh572/key639839
world2.com           /randomkey788gauh72/key63whjk
world3.com           /randomkey788gauh72/key63whjk
world4.com           /randomkeyhghgdh778/key67567
world1.com           /randomkeyhueh34778/key67uuu77
world2.com           /randomkeyJJJJ1111/key63333
world3.com           /randomkey7HHHH0000/key6333355k
world4.com           /randomkey8998382/key6hh77686

Você pode usar $'\n' em vez de "$NL" se o seu shell for compatível.

    
por 04.05.2016 / 08:49