Çizgileri yeniden sıralamayı önemsemiyorsanız ve GNU coreutils'iniz varsa (örneğin, shuf
6.0 sürümünde göründüğünden çok eski olmayan gömülü Linux veya Cygwin'de ), shuf
(“shuffle”) bir dosyanın satırlarını rastgele yeniden sıralar. Böylece dosyayı karıştırabilir ve ilk m satırını bir dosyaya geri kalanı başka bir dosyaya gönderebilirsiniz.
Bu gönderiyi yapmanın ideal bir yolu yok. Sadece zincirleme yapamazsınız head
ve tail
çünkü head
önünüzde tampon olur. Kullanabilirsiniz split
, ancak çıktı dosyası adlarıyla ilgili herhangi bir esneklik elde edemezsiniz. awk
Elbette kullanabilirsiniz :
<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'
Kullanabilirsiniz sed
, bu da büyük dosyalar için belirsiz ancak muhtemelen daha hızlıdır.
<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2
Veya tee
, platformunuz varsa verileri çoğaltmak için kullanabilirsiniz /dev/fd
; m küçükse sorun değil:
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
Taşınabilir olarak, her satırı sırayla göndermek için awk kullanabilirsiniz. Awk, rasgele sayı üretecini başlatmada çok iyi değildir; rasgelelik sadece kriptografi için kesinlikle uygun değildir, aynı zamanda sayısal simülasyonlar için bile çok iyi değildir. Tohum, bir saniyelik bir süreye sahip herhangi bir sistemdeki tüm awk invokasyonları için aynı olacaktır.
<input awk -v N=$(wc -l <input) -v m=3 '
BEGIN {srand()}
{
if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
--N;
}'
Daha iyi rasgeleliğe ihtiyacınız varsa, RNG'yi terbiyeli bir şekilde tohumlayan Perl'de de aynı şeyi yapabilirsiniz.
<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