ใช้ 'head' หรือ 'tail' ในไฟล์ข้อความขนาดใหญ่ - 19 GB


15

ฉันมีปัญหากับการดูส่วนของไฟล์ข้อความขนาดใหญ่มาก ไฟล์นี้มีขนาดประมาณ 19 GB ซึ่งใหญ่เกินกว่าจะรับชมได้อย่างแน่นอน

ฉันได้ลองhead 1และtail 1( head -n 1และtail -n 1) ด้วยคำสั่งทั้งสองรวมเข้าด้วยกันในรูปแบบต่างๆ (เพื่อให้ได้ชิ้นกลาง) โดยไม่มีโชค เครื่อง Linux ที่ใช้ Ubuntu 9.10 ไม่สามารถประมวลผลไฟล์นี้ได้

ฉันจะจัดการไฟล์นี้ได้อย่างไร เป้าหมายสูงสุดของฉันคือฝึกฝนในบรรทัด 45000000 และ 45000100


กำลังคิดที่จะเขียนสคริปต์ Python อย่างรวดเร็วเพื่ออ่านบรรทัดและพิมพ์สิ่งที่ฉันต้องการจัดเก็บ แต่ฉันสามารถจินตนาการว่ามันใช้เวลานาน ...
nicorellius

เส้นทั้งหมดมีความยาวเท่ากันหรือไม่?
พอล

@Paul - น่าเสียดายที่มันไม่ได้มีความยาวเท่ากัน
nicorellius

คุณสามารถพยายามsplitทำให้ไฟล์ขนาดใหญ่ทำงานได้ง่ายขึ้น
iglvzx

1
ตกลง. การประมวลผลไฟล์ที่มีขนาดใหญ่จะใช้เวลาดังนั้นคำตอบด้านล่างจะช่วยได้ หากคุณต้องการแยกเฉพาะส่วนที่คุณต้องการและสามารถประมาณค่าได้ว่าจะอยู่ที่ไหนคุณสามารถใช้ddรับบิตที่คุณอยู่หลังจากนั้น ตัวอย่างเช่นdd if=bigfile of=extractfile bs=1M skip=10240 count=5จะแยก 5MB จากไฟล์เริ่มต้นจากจุด 10GB
พอล

คำตอบ:


11

sedคุณควรใช้

sed -n -e 45000000,45000100p -e 45000101q bigfile > savedlines

สิ่งนี้บอกsedให้พิมพ์บรรทัดที่ 45000000-45000100 รวมและออกจากบรรทัด 45000101


1
มันยังช้ามากเหมือนหัว -45000000,45000100p bigfile | tail -100> hiddenlines
Dmitry Polushkin

tail+|headเร็วขึ้นโดยดี 10-15%
ริช

4

สร้างฐานข้อมูล MySQL ด้วยตารางเดียวซึ่งมีเขตข้อมูลเดียว จากนั้นนำเข้าไฟล์ของคุณไปยังฐานข้อมูล สิ่งนี้จะทำให้ง่ายต่อการค้นหาบรรทัด

ฉันไม่คิดว่าจะมีอะไรเร็วกว่านี้อีก (ถ้าheadและtailล้มเหลวไปแล้ว) ในที่สุดแอปพลิเคชันที่ต้องการค้นหาบรรทัดnต้องค้นหาไฟล์ทั้งหมดจนกว่าจะพบnบรรทัดใหม่ หากไม่มีการค้นหา (line-index to byte offset ลงในไฟล์) จะไม่มีประสิทธิภาพที่ดีกว่านี้

เมื่อพิจารณาว่ามันง่ายเพียงใดในการสร้างฐานข้อมูล MySQL และนำเข้าข้อมูลเข้ามาฉันรู้สึกว่านี่เป็นวิธีที่ปฏิบัติได้จริง

นี่คือวิธีที่จะทำ:

DROP DATABASE IF EXISTS helperDb;
CREATE DATABASE `helperDb`;
CREATE TABLE `helperDb`.`helperTable`( `lineIndex` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `lineContent` MEDIUMTEXT , PRIMARY KEY (`lineIndex`) );
LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable (lineContent);
SELECT lineContent FROM helperTable WHERE ( lineIndex > 45000000 AND lineIndex < 45000100 );

/tmp/my_large_file จะเป็นไฟล์ที่คุณต้องการอ่าน

ไวยากรณ์ที่ถูกต้องในการนำเข้าไฟล์ที่มีค่าคั่นด้วยแท็บในแต่ละบรรทัดคือ:

LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable FIELDS TERMINATED BY '\n' (lineContent);

ข้อได้เปรียบที่สำคัญอีกประการหนึ่งคือถ้าคุณตัดสินใจแยกชุดของบรรทัดในภายหลังคุณไม่ต้องรอเป็นชั่วโมงในการประมวลผลอีกครั้ง (เว้นแต่คุณจะลบฐานข้อมูลของหลักสูตร)


ดังนั้นนี่เป็นทางออกที่ดีอย่างแน่นอน ฉันได้มันไปทำงานกับsedคำสั่งด้านล่างและระบุบรรทัดของฉัน แต่ตอนนี้ฉันมีคำถามติดตามว่าวิธีฐานข้อมูลอาจเหมาะกว่า ตอนนี้ฉันต้องลบสองสามร้อยบรรทัดออกจากไฟล์
nicorellius

ฉันแน่ใจว่าsedสามารถทำได้เช่นกัน แน่นอนถ้าคุณมีข้อมูลในฐานข้อมูลมันจะไม่สำคัญที่จะส่งออกไฟล์ใหม่ที่มีเพียงบรรทัดที่คุณต้องการ
Der Hochstapler

ขอบคุณอีกครั้ง. ฉันsedตอบคำถาม (เพราะมันทำให้ฉันมีความสุขมากขึ้นทันที; -) แต่ให้คะแนนคุณเพราะฉันจะใช้วิธีการของคุณในอนาคต ฉันรู้สึกทราบซึ้ง.
nicorellius

1
คุณสามารถลองเพิ่ม a FIELDS TERMINATED BY '\n'ลงในLOAD DATAบรรทัดได้
Der Hochstapler

1
ฉันขอโทษมีข้อผิดพลาดในรหัสของฉัน ฉันยังเพิ่มไวยากรณ์ที่ถูกต้องสำหรับกรณีของคุณ (ทดสอบในครั้งนี้)
Der Hochstapler

1

สองเครื่องมือเก่าที่ดีสำหรับไฟล์ขนาดใหญ่และjoin splitคุณสามารถใช้ split พร้อม--lines=<number>ตัวเลือกที่ตัดไฟล์เป็นหลายไฟล์ในขนาดที่กำหนด

split --lines=45000000 huge_file.txtเช่น ส่วนที่เป็นผลลัพธ์จะเป็น xa, xb เป็นต้นจากนั้นคุณสามารถheadส่วนxbซึ่งจะรวมถึงบรรทัดที่คุณต้องการ นอกจากนี้คุณยังสามารถ 'เข้าร่วม' ไฟล์กลับไปที่ไฟล์ขนาดใหญ่ไฟล์เดียว


เยี่ยมมากขอบคุณฉันลืมคำสั่ง split โดยสิ้นเชิง
siliconrockstar

0

คุณมีเครื่องมือที่เหมาะสม แต่ใช้ไม่ถูกต้อง ขณะที่ก่อนหน้านี้ตอบมากกว่าที่ U & L, tail -n +X file | head -n Y(หมายเหตุ+) เป็น 10-15% เร็วกว่าsedสำหรับสาย Y เริ่มต้นที่ X. และสิ่งอำนวยความสะดวกที่คุณจะได้ไม่ต้องชัดเจนกระบวนการเช่นเดียวกับexitsed

tail จะอ่านและทิ้งบรรทัด X-1 บรรทัดแรก (ไม่มีทางอยู่รอบ ๆ ) จากนั้นอ่านและพิมพ์บรรทัดต่อไปนี้ หัวจะอ่านและพิมพ์จำนวนบรรทัดที่ต้องการจากนั้นออก เมื่อออกจากส่วนหัว tail จะรับสัญญาณ SIGPIPE และตายดังนั้นมันจะไม่อ่านมากกว่าค่าของขนาดบัฟเฟอร์ (โดยทั่วไปคือไม่กี่กิโลไบต์) ของบรรทัดจากไฟล์อินพุต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.