Якщо ви не проти перепорядкувати рядки та маєте GNU coreutils (тобто на невбудованому Linux або Cygwin, не надто старовинному з моменту shufпояви у версії 6.0), shuf(“shuffle”) впорядковує рядки файлу випадковим чином. Таким чином, ви можете перетасувати файл і пересилати перші m рядків в один файл, а інші в інший.
Немає ідеального способу зробити це відправлення. Ви не можете просто ланцюг headі tailтому, headщо буфер вперед. Можна використовувати split, але ви не отримуєте будь-якої гнучкості стосовно імен вихідних файлів. Можна awk, звичайно, використовувати:
<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'
Ви можете використовувати sed, що малозрозуміло, але можливо швидше для великих файлів.
<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2
Або ви можете використовувати teeдля дублювання даних, якщо ваша платформа має /dev/fd; це нормально, якщо m невеликий:
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
Портативно, ви можете використовувати awk для відправки кожного рядка по черзі. Зауважте, що awk не дуже добре ініціалізує свій генератор випадкових чисел; випадковість не тільки точно не підходить для криптографії, але навіть не дуже добре для чисельних моделювання. Насіння буде однаковим для всіх викликань у будь-якій системі протягом однієї секунди.
<input awk -v N=$(wc -l <input) -v m=3 '
BEGIN {srand()}
{
if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
--N;
}'
Якщо вам потрібна краща випадковість, ви можете зробити те ж саме в Perl, який пристойно висіває свій 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