Se você não se importa de reordenar as linhas e tiver o GNU coreutils (por exemplo, no Linux ou Cygwin não incorporado, não muito antigo desde que shuf
apareceu na versão 6.0), shuf
("shuffle") reordena as linhas de um arquivo aleatoriamente. Assim, você pode embaralhar o arquivo e despachar as primeiras m linhas em um arquivo e o restante em outro.
Não existe uma maneira ideal de fazer esse envio. Você não pode simplesmente encadear head
e tail
porque head
ficaria mais à frente. Você pode usar split
, mas não tem flexibilidade com relação aos nomes dos arquivos de saída. Você pode usar awk
, é claro:
<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'
Você pode usar sed
, o que é obscuro, mas possivelmente mais rápido, para arquivos grandes.
<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2
Ou você pode usar tee
para duplicar os dados, se sua plataforma tiver /dev/fd
; tudo bem se m for pequeno:
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
Portably, você pode usar o awk para despachar cada linha por vez. Observe que o awk não é muito bom em inicializar seu gerador de números aleatórios; a aleatoriedade não é apenas definitivamente não adequada para criptografia, mas nem muito boa para simulações numéricas. A semente será a mesma para todas as invocações do awk em qualquer sistema dentro de um período de um segundo.
<input awk -v N=$(wc -l <input) -v m=3 '
BEGIN {srand()}
{
if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
--N;
}'
Se você precisar de uma aleatoriedade melhor, poderá fazer o mesmo no Perl, que semeia seu RNG decentemente.
<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