Comment sortinger sur la première colonne toutes les 4 lignes dans un file avec une key dans la deuxième colonne

Exemple de file:

la première colonne peut avoir un set fixe de 4 valeurs non ordonnées world1.com,world2.com,world3.com or world4.com

deuxième colonne est une key appartient à chaque ligne de sorte que chacun des quatre sets a une key random unique.

 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 

etc

Sortie souhaitée:

 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 

Pour organiser les files par monde:

 $ 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 

Comment ça marche

Nous pouvons utiliser grep pour sélectionner les lignes pour chaque monde:

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

paste combine les lignes de plusieurs files. La command paste pourrait ressembler à ceci:

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

Nous n'avons pas besoin de créer de vrais files pour chaque monde. Au lieu de cela, nous pouvons créer des objects de type file pour chacun en utilisant la substitution de process :

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

La substitution de process est prise en charge par bash, zsh et AT & T ksh88 et ksh93 mais pas par tiret, pdksh ou mksh.

Fonctionnalité supplémentaire: sorting par key

Pour illustrer la flexibilité de cette approche, nous sortingerons les keys de chaque monde. Note: le sorting divise les sets de lignes. Ne l'utilisez pas si vous voulez garder les sets set.

Nous pouvons séparer les mondes en utilisant grep , puis sort chacun, puis merge les lignes set en utilisant la 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 

Notez que le sort dépend des parameters régionaux. Différents locales peuvent entraîner des ordres différents.

 #!/usr/bin/perl use ssortingct; 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); 

donner le nom du file d'input comme argument de command line, ex:

 ./sort_blocks.pl data.txt 

Ce script perl devrait fonctionner avec n'importe quel nombre de domaines (premiers champs) avec un nombre quelconque de keys (deuxièmes champs) par domaine. Les domaines peuvent avoir le même nombre de keys, mais ne sont pas obligés de le faire.

Il construit un hachage ( %domains ) avec chaque élément du hachage contenant un tableau de keys. En faisant cela, il garde la trace du plus grand nombre de keys vues pour l'un des domaines.

Après avoir lu toutes les inputs, il imprime chaque key existante pour chaque domaine.

 #! /usr/bin/perl use ssortingct; 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])); } } 

Sortie:

 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 

Si vous ne souhaitez pas que le même nombre de keys soit considéré comme une erreur, remplacez la ligne print "$domain\..... dans le dernier bloc de code par:

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

replace warn with die si vous voulez que ce soit une erreur fatale.

 $ 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 

Sur le système 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 

Vous pouvez utiliser $'\n' au lieu de "$NL" si votre shell est supporté.