หากคุณไม่คิดใหม่ในการจัดเรียงบรรทัดใหม่และคุณมี GNU coreutils (เช่นบน Linux หรือ Cygwin ที่ไม่ได้ฝังตัวไม่เก่าเกินไปนับตั้งแต่shuf
ปรากฏในเวอร์ชัน 6.0), shuf
(“ สับเปลี่ยน”) เรียงลำดับบรรทัดของไฟล์แบบสุ่ม ดังนั้นคุณสามารถสับเปลี่ยนไฟล์และส่งบรรทัด 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 นั้นไม่ค่อยดีนักในการเริ่มต้นตัวสร้างตัวเลขแบบสุ่ม การสุ่มไม่เพียง แต่ไม่เหมาะสำหรับการเข้ารหัสเท่านั้น แต่ไม่เหมาะสำหรับการจำลองเชิงตัวเลข เมล็ดจะเหมือนกันสำหรับการร้องขอ 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