Sử dụng 'đầu' hoặc 'đuôi' trên tệp văn bản HUGE - 19 GB


14

Tôi có một vấn đề với việc xem các đoạn của một tệp văn bản rất lớn. Tệp này, xấp xỉ 19 GB, rõ ràng là quá lớn để xem bằng bất kỳ phương tiện truyền thống nào.

Tôi đã thử head 1tail 1( head -n 1tail -n 1) với cả hai lệnh được nối với nhau theo nhiều cách khác nhau (để có được một mảnh ở giữa) mà không gặp may mắn. Máy Linux của tôi chạy Ubuntu 9.10 không thể xử lý tệp này.

Làm thế nào để tôi xử lý tập tin này? Mục tiêu cuối cùng của tôi là trau dồi trên các dòng 45000000 và 45000100.


Nghĩ đến việc viết một kịch bản Python nhanh để đọc các dòng và in những dòng tôi cần để gửi, nhưng tôi có thể tưởng tượng điều này mất nhiều thời gian ...
nicorellius

Có phải tất cả các dòng có cùng chiều dài?
Paul

@Paul - Thật không may, chúng không cùng chiều dài.
nicorellius

Bạn có thể cố gắng splitlàm cho tệp lớn dễ làm việc hơn.
iglvzx

1
Đồng ý. Bất kỳ việc xử lý tệp lớn nào cũng sẽ mất thời gian, vì vậy các câu trả lời dưới đây sẽ giúp ích cho việc đó. Nếu bạn muốn trích xuất chỉ phần bạn đang tìm kiếm và có thể ước tính khoảng nơi bạn có thể sử dụng ddđể lấy bit bạn đang theo dõi. Ví dụ: dd if=bigfile of=extractfile bs=1M skip=10240 count=5sẽ trích xuất 5 MB từ tệp bắt đầu từ điểm 10 GB.
Paul

Câu trả lời:


11

Bạn nên sử dụng sed.

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

Điều này nói sedvới các dòng in bao gồm 45000000-45000100 và thoát khỏi dòng 45000101.


1
Nó vẫn rất chậm, gần giống như đầu -45000000,45000100p bigfile | đuôi -100> dòng lưu
Dmitry Polushkin

tail+|headnhanh hơn khoảng 10 - 15%.
Erich

4

Tạo một cơ sở dữ liệu MySQL với một bảng duy nhất có một trường duy nhất. Sau đó nhập tệp của bạn vào cơ sở dữ liệu. Điều này sẽ làm cho nó rất dễ dàng để tìm kiếm một dòng nhất định.

Tôi không nghĩ bất cứ điều gì khác có thể nhanh hơn (nếu headtailđã thất bại). Cuối cùng, ứng dụng muốn tìm dòng nphải tìm kiếm trong toàn bộ tệp cho đến khi tìm thấy ndòng mới. Nếu không có một số loại tra cứu (chỉ số dòng đến byte bù vào tệp), hiệu suất tốt hơn có thể đạt được.

Với việc dễ dàng tạo cơ sở dữ liệu MySQL và nhập dữ liệu vào đó, tôi cảm thấy như đây là một cách tiếp cận khả thi.

Đây là cách làm:

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 sẽ là tập tin bạn muốn đọc.

Cú pháp đúng để nhập tệp có giá trị được phân định bằng tab trên mỗi dòng là:

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

Một ưu điểm lớn khác của điều này là, nếu sau này bạn quyết định trích xuất một bộ dòng khác, bạn không phải đợi hàng giờ để xử lý lại (trừ khi bạn xóa cơ sở dữ liệu).


Vì vậy, đây là một giải pháp tốt, thực sự. Tôi đã nhận nó để làm việc với sedlệnh bên dưới, và xác định các dòng của tôi. Nhưng bây giờ tôi có một câu hỏi tiếp theo rằng phương pháp cơ sở dữ liệu có thể phù hợp hơn. Bây giờ tôi cần xóa vài trăm dòng khỏi tệp.
nicorellius

Tôi chắc chắn sedcó thể làm điều đó là tốt. Tất nhiên, nếu bạn có dữ liệu trong cơ sở dữ liệu, việc xuất một tệp mới chỉ với các dòng bạn muốn là chuyện nhỏ.
Der Hochstapler

Cảm ơn một lần nữa. Tôi đã sedtrả lời (vì nó mang lại cho tôi niềm vui ngay lập tức hơn; -) nhưng đã cho bạn một cuộc bỏ phiếu vì tôi sẽ sử dụng phương pháp của bạn trong tương lai. Tôi rât cảm kich.
nicorellius

1
Bạn có thể thử thêm một FIELDS TERMINATED BY '\n'đến LOAD DATAdòng.
Der Hochstapler

1
Tôi xin lỗi, có một lỗi trong mã của tôi. Tôi cũng đã thêm cú pháp đúng cho trường hợp của bạn (đã thử nghiệm lần này).
Der Hochstapler

1

Hai công cụ cũ tốt cho các tập tin lớn là joinsplit. Bạn có thể sử dụng chia với --lines=<number>tùy chọn cắt tệp thành nhiều tệp có kích thước nhất định.

Ví dụ split --lines=45000000 huge_file.txt. Các phần kết quả sẽ là xa, xb, v.v. Sau đó, bạn có thể headphần xb sẽ bao gồm các dòng bạn muốn. Bạn cũng có thể 'tham gia' các tệp trở lại một tệp lớn.


Tuyệt vời, cảm ơn bạn, tôi hoàn toàn quên mất lệnh chia.
siliconrockstar

0

Bạn có các công cụ phù hợp nhưng đang sử dụng chúng không chính xác. Như đã trả lời trước tại U & L, tail -n +X file | head -n Y(lưu ý +) nhanh hơn 10 - 15% so sedvới các dòng Y bắt đầu từ X. Và thuận tiện, bạn không phải xử lý rõ ràng exitquy trình như với sed.

đuôi sẽ đọc và loại bỏ các dòng X-1 đầu tiên (không có cách nào khác), sau đó đọc và in các dòng sau. Head sẽ đọc và in số dòng yêu cầu, sau đó thoát. Khi thoát ra, đuôi nhận được tín hiệu SIGPIPE và chết, do đó, nó sẽ không đọc được nhiều hơn giá trị của kích thước bộ đệm (thường là vài kilobyte) từ tệp đầu vào.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.