เลือกบรรทัดสุ่มจากไฟล์


240

ในสคริปต์ Bash ฉันต้องการเลือก N สุ่มบรรทัดจากอินพุตไฟล์และเอาต์พุตไปยังไฟล์อื่น

สิ่งนี้สามารถทำได้?


จัดเรียงไฟล์แบบสุ่มและเลือก N บรรทัดแรก
Piotr Praszmo


31
นี่ไม่ซ้ำกัน - เขาต้องการ N Lines กับ 1 บรรทัด
OneSolitaryNoob


1
ฉันไม่เห็นด้วยsort -Rเพราะใช้งานมากเกินไปโดยเฉพาะไฟล์ที่มีความยาว คุณสามารถใช้$RANDOM, % wc -l, jot, sed -n(เมนูstackoverflow.com/a/6022431/563329 ) และฟังก์ชั่นทุบตี (อาร์เรย์การเปลี่ยนเส้นทางคำสั่ง ฯลฯ ) เพื่อกำหนดของคุณเองpeekฟังก์ชั่นซึ่งจะทำงานจริงในไฟล์ 5,000,000 เส้น
isomorphismes

คำตอบ:


627

ใช้shufกับ-nตัวเลือกที่แสดงด้านล่างเพื่อรับNสายสุ่ม:

shuf -n N input > output

2
หากคุณต้องการเพียงชุดสุ่มของบรรทัดไม่ใช่ลำดับแบบสุ่มดังนั้น shuf จะไม่มีประสิทธิภาพมาก (สำหรับไฟล์ขนาดใหญ่): ดีกว่าคือทำการสุ่มตัวอย่างอ่างเก็บน้ำตามคำตอบนี้
petrelharp

ฉันเรียกใช้ไฟล์ 500M แถวเพื่อแยก 1,000 แถวและใช้เวลา 13 นาที ไฟล์ไม่ได้รับการเข้าถึงในเดือนและอยู่ในไดรฟ์ Amazon EC2 SSD
T. Brian Jones

ดังนั้นในสาระสำคัญสุ่มมากขึ้นที่sort -R?
Mona Jalal

1
@MonaJalal ไม่เร็วขึ้นเนื่องจากไม่จำเป็นต้องเปรียบเทียบบรรทัดเลย
rogerdpack

ในที่สุดมันให้ผลบรรทัดเดียวกันมากกว่าหนึ่งครั้งหรือไม่?
Frederick Nord

161

จัดเรียงไฟล์แบบสุ่มและเลือก100บรรทัดแรก:

$ sort -R input | head -n 100 >output

43
sortจริง ๆ แล้วเรียงลำดับบรรทัดที่เหมือนกันด้วยกันดังนั้นหากคุณอาจมีบรรทัดที่ซ้ำกันและคุณมีshuf(เครื่องมือ gnu) ติดตั้งจะดีกว่าที่จะใช้มันสำหรับสิ่งนี้
เควิน

22
andalso นี้แน่นอนจะทำให้คุณรอมากถ้าคุณมีไฟล์ขนาดใหญ่มาก - 80kk สาย - ในขณะที่shuf -nทำหน้าที่ค่อนข้างทันที
รูเบนส์

28
sort -R ไม่สามารถใช้งานได้กับ Mac OS X (10.9)
Mirko Ebert

3
@ tfb785: sort -Rอาจเป็นตัวเลือก GNU, ติดตั้ง GNU coreutils btw shufยังเป็นส่วนหนึ่งของ coreutils
jfs

1
@JFSebastian รหัส: sort -R input | head -n <num_lines>. ไฟล์อินพุตคือ 279GB โดยมี 2bi + บรรทัด ไม่สามารถแบ่งปันได้ อย่างไรก็ตามประเด็นคือคุณสามารถเก็บบางบรรทัดไว้ในหน่วยความจำด้วยการสลับเพื่อทำการสุ่มเลือกสิ่งที่จะส่งออก การเรียงลำดับจะเรียงลำดับไฟล์ทั้งหมดโดยไม่คำนึงถึงความต้องการของคุณ
รูเบนส์

18

ดีตามความคิดเห็นในคำตอบ shuf เขา shuffed 78,000 000 000 บรรทัดในไม่กี่นาที

รับคำท้า...

แก้ไข: ฉันเอาชนะบันทึกของตัวเอง

powershuf ทำมันใน 0.047 วินาที

$ time ./powershuf.py -n 10 --file lines_78000000000.txt > /dev/null 
./powershuf.py -n 10 --file lines_78000000000.txt > /dev/null  0.02s user 0.01s system 80% cpu 0.047 total

สาเหตุที่เร็วมากฉันไม่อ่านไฟล์ทั้งหมดและย้ายตัวชี้ไฟล์ 10 ครั้งแล้วพิมพ์บรรทัดหลังตัวชี้

Gitlab Repo

ความพยายามเก่า

ก่อนอื่นฉันต้องการไฟล์ 78.000.000.000 บรรทัด:

seq 1 78 | xargs -n 1 -P 16 -I% seq 1 1000 | xargs -n 1 -P 16 -I% echo "" > lines_78000.txt
seq 1 1000 | xargs -n 1 -P 16 -I% cat lines_78000.txt > lines_78000000.txt
seq 1 1000 | xargs -n 1 -P 16 -I% cat lines_78000000.txt > lines_78000000000.txt

สิ่งนี้ทำให้ฉันได้ไฟล์กับ78 พันล้าน newlines ;-)

ตอนนี้สำหรับส่วน shuf:

$ time shuf -n 10 lines_78000000000.txt










shuf -n 10 lines_78000000000.txt  2171.20s user 22.17s system 99% cpu 36:35.80 total

คอขวดคือ CPU และไม่ได้ใช้หลายเธรดมันตรึง 1 คอร์ที่ 100% ที่ 15 อื่นไม่ได้ใช้

Python เป็นสิ่งที่ฉันใช้เป็นประจำดังนั้นฉันจึงใช้เพื่อทำให้เร็วขึ้น:

#!/bin/python3
import random
f = open("lines_78000000000.txt", "rt")
count = 0
while 1:
  buffer = f.read(65536)
  if not buffer: break
  count += buffer.count('\n')

for i in range(10):
  f.readline(random.randint(1, count))

สิ่งนี้ทำให้ฉันใช้เวลาไม่กี่นาที:

$ time ./shuf.py         










./shuf.py  42.57s user 16.19s system 98% cpu 59.752 total

ฉันทำสิ่งนี้บน Lenovo X1 Extreme 2nd Gen ด้วย i9 และ Samsung NVMe ซึ่งให้ความเร็วในการอ่านและเขียนมากมาย

ฉันรู้ว่ามันจะเร็วขึ้น แต่ฉันจะออกจากห้องเพื่อให้คนอื่นลอง

แหล่งที่มาของตัวนับบรรทัด: Luther Blissett


ตามคำอธิบายของคุณเกี่ยวกับฟังก์ชันการทำงานภายในของ powershuf ดูเหมือนว่ามันจะสุ่ม การใช้ไฟล์ที่มีเพียงสองบรรทัดบรรทัดหนึ่งยาว 1 อักขระและอีก 20 อักขระยาวฉันคาดว่าทั้งสองบรรทัดจะได้รับการคัดเลือกโดยมีโอกาสเท่ากัน สิ่งนี้ไม่ได้เกิดขึ้นกับโปรแกรมของคุณ
xhienne
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.