Если вы не возражаете переупорядочить строки и у вас есть 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
; это нормально, если м мало:
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
В частности, вы можете использовать awk для отправки каждой строки по очереди. Обратите внимание, что 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, который прилично заполняет его ГСЧ.
<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