Si cela ne vous dérange pas de réorganiser les lignes et que vous avez des coreutils GNU (c'est-à-dire sur Linux non intégré ou Cygwin, pas trop ancien depuis shuf
apparu dans la version 6.0), shuf
("shuffle") réorganise les lignes d'un fichier de manière aléatoire. Vous pouvez donc mélanger le fichier et répartir les m premières lignes dans un fichier et le reste dans un autre.
Il n'y a pas de moyen idéal pour faire cette dépêche. Vous ne pouvez pas simplement enchaîner head
et tail
parce head
que tamponner à l'avance. Vous pouvez utiliser split
, mais vous n'obtenez aucune flexibilité en ce qui concerne les noms des fichiers de sortie. Vous pouvez awk
bien sûr utiliser :
<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'
Vous pouvez utiliser sed
ce qui est obscur mais peut-être plus rapide pour les gros fichiers.
<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2
Ou vous pouvez utiliser tee
pour dupliquer les données, si votre plate-forme a /dev/fd
; c'est ok si m est petit:
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
De manière portable, vous pouvez utiliser awk pour distribuer chaque ligne tour à tour. Notez que awk n'est pas très bon pour initialiser son générateur de nombres aléatoires; le caractère aléatoire n'est pas seulement définitivement inapproprié pour la cryptographie, mais même pas très bon pour les simulations numériques. La graine sera la même pour toutes les invocations awk sur n'importe quel système avec une période d'une seconde.
<input awk -v N=$(wc -l <input) -v m=3 '
BEGIN {srand()}
{
if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
--N;
}'
Si vous avez besoin d'un meilleur caractère aléatoire, vous pouvez faire la même chose en Perl, qui amorce décemment son RNG.
<input perl -e '
open OUT1, ">", "output1" or die $!;
open OUT2, ">", "output2" or die $!;
my $N = `wc -l <input`;
my $m = $ARGV[0];
while (<STDIN>) {
if (rand($N) < $m) { --$m; print OUT1 $_; } else { print OUT2 $_; }
--$N;
}
close OUT1 or die $!;
close OUT2 or die $!;
' 42