Se non ti dispiace riordinare le linee e hai coreutils GNU (cioè su Linux non incorporato o Cygwin, non troppo antico da quando è shuf
apparso nella versione 6.0), shuf
("shuffle") riordina le linee di un file in modo casuale. Quindi puoi mescolare il file e inviare le prime m righe in un file e il resto in un altro.
Non esiste un modo ideale per fare quella spedizione. Non puoi semplicemente concatenare head
e tail
perché head
sarebbe tampone in anticipo. È possibile utilizzare split
, ma non si ottiene alcuna flessibilità rispetto ai nomi dei file di output. Puoi awk
ovviamente usare :
<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'
È possibile utilizzare sed
, che è oscuro ma forse più veloce per file di grandi dimensioni.
<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2
Oppure puoi usare tee
per duplicare i dati, se la tua piattaforma ha /dev/fd
; va bene se m è piccolo:
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
Portabilmente, puoi usare awk per spedire ogni riga a turno. Nota che awk non è molto bravo a inizializzare il suo generatore di numeri casuali; la casualità non è sicuramente non solo adatta per la crittografia, ma nemmeno molto buona per le simulazioni numeriche. Il seme sarà lo stesso per tutte le invocazioni awk su qualsiasi sistema entro un periodo di un secondo.
<input awk -v N=$(wc -l <input) -v m=3 '
BEGIN {srand()}
{
if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
--N;
}'
Se hai bisogno di una migliore casualità, puoi fare la stessa cosa in Perl, che semina decentemente il suo 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