Si no le importa reordenar las líneas y tiene coreutils de GNU (es decir, en Linux o Cygwin no integrados, no demasiado antiguos desde que shuf
apareció en la versión 6.0),shuf
("barajar") reordena las líneas de un archivo al azar. Por lo tanto, puede mezclar el archivo y enviar las primeras m líneas a un archivo y el resto a otro.
No hay una forma ideal de hacer ese despacho. No puedes simplemente encadenar head
y tail
porque head
se amortiguaría. Puede usar split
, pero no obtiene ninguna flexibilidad con respecto a los nombres de los archivos de salida. Puedes usar awk
, por supuesto:
<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'
Puede usarlo sed
, que es oscuro pero posiblemente más rápido para archivos grandes.
<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2
O puede usar tee
para duplicar los datos, si su plataforma lo ha hecho /dev/fd
; está bien si m es pequeño:
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
Portablemente, puede usar awk para despachar cada línea por turno. Tenga en cuenta que awk no es muy bueno para inicializar su generador de números aleatorios; la aleatoriedad no solo definitivamente no es adecuada para la criptografía, sino que ni siquiera es muy buena para las simulaciones numéricas. La semilla será la misma para todas las invocaciones awk en cualquier sistema dentro de un período de un segundo.
<input awk -v N=$(wc -l <input) -v m=3 '
BEGIN {srand()}
{
if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
--N;
}'
Si necesita una mejor aleatoriedad, puede hacer lo mismo en Perl, que siembra decentemente su 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