Nếu bạn không nhớ sắp xếp lại các dòng và bạn có GNU coreutils (tức là trên Linux hoặc Cygwin không được nhúng, không quá cổ kể từ khi shuf
xuất hiện trong phiên bản 6.0), shuf
(tạm thời xáo trộn) sẽ sắp xếp lại các dòng của tệp một cách ngẫu nhiên. Vì vậy, bạn có thể xáo trộn tệp và gửi các dòng m đầu tiên vào một tệp và phần còn lại vào một tệp khác.
Không có cách lý tưởng để thực hiện công văn đó. Bạn không thể xâu chuỗi head
và tail
vì head
sẽ đệm trước. Bạn có thể sử dụng split
, nhưng bạn không có được sự linh hoạt nào đối với tên tệp đầu ra. Bạn có thể sử dụng awk
, tất nhiên:
<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'
Bạn có thể sử dụng sed
, điều này tối nghĩa nhưng có thể nhanh hơn đối với các tệp lớn.
<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2
Hoặc bạn có thể sử dụng tee
để sao chép dữ liệu, nếu nền tảng của bạn có /dev/fd
; Không sao nếu m nhỏ:
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
Có thể sử dụng awk để gửi lần lượt từng dòng. Lưu ý rằng awk không tốt lắm trong việc khởi tạo trình tạo số ngẫu nhiên của nó; tính ngẫu nhiên không chỉ chắc chắn không phù hợp với mật mã, mà thậm chí còn không tốt cho mô phỏng số. Hạt giống sẽ giống nhau cho tất cả các yêu cầu awk trên bất kỳ hệ thống nào trong khoảng thời gian một giây.
<input awk -v N=$(wc -l <input) -v m=3 '
BEGIN {srand()}
{
if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
--N;
}'
Nếu bạn cần sự ngẫu nhiên tốt hơn, bạn có thể làm điều tương tự trong Perl, hạt giống RNG của nó một cách dứt khoát.
<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