Thay thế văn bản nhanh chóng trong tệp rất lớn


25

Tôi có tệp văn bản 25 GB cần một chuỗi thay thế chỉ trên một vài dòng. Tôi có thể sử dụng sedthành công nhưng phải mất một thời gian dài để chạy.

sed -i 's|old text|new text|g' gigantic_file.sql

Có cách nào nhanh hơn để làm điều này?


Bạn có biết số dòng nơi văn bản để thay thế là? Nếu không, lựa chọn duy nhất của bạn để tăng tốc nó là để có được một máy tính nhanh hơn. Thực tế là bạn có một lượng lớn dữ liệu có nghĩa là sẽ mất một lượng lớn thời gian để tìm kiếm thông qua nó.
Vua David

Tôi có thể grep cho số dòng khá nhanh, vì vậy có.
eisaacson

Bạn cũng có thể sử dụng nhiều lõi CPU để tăng tốc nó - rankf Focus.com/use-cpu-cores-linux-commands
ahaswer 14/2/2016

Đừng sử dụng sed cho các tệp lớn. Hãy xem vi hoặc vim thay thế.
MikeJRamsey56

Câu trả lời:


26

Bạn co thể thử:

sed -i '/old text/ s//new text/g' gigantic_file.sql

Từ tài liệu tham khảo này :

Tối ưu hóa cho TỐC ĐỘ: Nếu cần tăng tốc độ thực thi (do các tệp đầu vào lớn hoặc bộ xử lý chậm hoặc đĩa cứng), việc thay thế sẽ được thực hiện nhanh hơn nếu biểu thức "tìm" được chỉ định trước khi đưa ra "s /.../. ../" chỉ dẫn.

Đây là một so sánh trên một tập tin 10G. Trước:

$ time sed -i 's/original/ketan/g' wiki10gb
real    5m14.823s
user    1m42.732s
sys     1m51.123s

Sau:

$ time sed -i '/ketan/ s//original/g' wiki10gb
real    4m33.141s
user    1m20.940s
sys     1m44.451s

Cuối cùng sedlà sai chính tả. Tôi đã chỉnh sửa bài đăng này ngày hôm qua để sửa sedlệnh cuối cùng nên time sed -i '/original/ s//ketan/g' wiki10gbvà không time sed -i '/ketan/ s//original/g' wiki10gb. Hôm nay tôi hoàn nguyên bản chỉnh sửa của mình vì 1. thời gian không còn khớp lệnh và 2. Tôi đã thực hiện cùng một thử nghiệm với GNU sed trên tệp 3+ GB và tôi không thấy bất kỳ sự khác biệt nào giữa hai sedlựa chọn thay thế. Tôi nghi ngờ rằng sự khác biệt về thời gian là do lỗi chính tả.
xhienne

@xhienne Tôi không chắc ý của bạn là gì khi viết sai chính tả. Trong lần chạy đầu tiên, tôi thay thế từ 'gốc' bằng 'ketan' và trong lần thứ hai tôi thay thế thuật ngữ 'ketan' bằng thuật ngữ 'gốc' dẫn đến số lần thay thế bằng nhau trong cả hai trường hợp.
mkc

1
Tôi đã áp dụng một "sửa chữa" được báo cáo bởi một người dùng mới với danh tiếng không đủ. Bây giờ tôi hiểu những gì bạn đã làm. Tuy nhiên, nếu bạn muốn chứng minh rằng một cú pháp tốt hơn một cú pháp khác, bạn phải thực hiện chính xác thao tác tương tự không phải ở đây (CPU-khôn ngoan, tìm kiếm chuỗi 5 char không giống như tìm kiếm một Chuỗi 7 ký tự). Hơn nữa, loại thử nghiệm này trên tệp 10 GB phụ thuộc rất nhiều vào tải máy của bạn (CPU, đĩa). Tôi đã thấy rất nhiều biến động trong timekết quả cá nhân, nhưng tất cả, không có sự khác biệt về thời gian.
xhienne

Tôi tin rằng điều này có liên quan - xem câu trả lời được chấp nhận ở đây, stackoverflow.com/questions/11145270/ Khăn >> sed truyền toàn bộ tệp, nhưng như đã lưu ý trong câu trả lời này, việc chỉ định số dòng (nếu biết) sẽ giúp: trong trường hợp của tôi , tốc độ thực thi tăng gấp 2 lần (GNU sed 4.5). Bạn có thể grep -n hoặc ripgrep (rg) để tìm số dòng, dựa trên tìm kiếm mẫu. Trong thực tế, việc chỉ định số dòng giống như có kết quả tìm kiếm trên tệp đó, theo câu trả lời ở trên.
Victoria Stuart

1

Câu trả lời ngắn gọn là "Không" - yếu tố giới hạn của bạn đối với loại hoạt động này là đĩa IO. Không có cách nào để truyền phát 25GB đĩa nhanh hơn. Bạn có thể nhận được một cải tiến nhỏ nếu bạn không chỉnh sửa tại chỗ và bạn viết kết quả của sedmột ổ đĩa riêng (nếu bạn có sẵn một ổ đĩa) - bởi vì cách đó bạn có thể đọc từ một, trong khi viết cho một ổ đĩa khác và có một chút Kết quả là ít tranh cãi.

Bạn thể tăng tốc lên một chút bằng cách không sử dụng công cụ regex cho mỗi dòng - vì vậy, ví dụ như sử dụng perl (tôi khá chắc chắn rằng bạn có thể làm điều này với sednhưng tôi không biết cú pháp) - điều này sẽ bắt đầu từ dòng 10.000 trở đi.

perl -pe '$. > 10_000 && s/old_text/new_text/g' 

Và nếu có bất kỳ loại phức tạp nào trong RE (siêu nhân vật) thì việc giảm thiểu chúng sẽ giúp cải thiện hiệu quả của công cụ regex một chút .


1
Trong sed đó sẽ làsed -i '10000,$ s/old_text/new_text/g'
Dani_l

Đáng yêu. Tôi không biết sedso sánh như thế nào - Tôi giả sử nhanh hơn một chút, nhưng không nhiều vì kích thước tệp.
Sobrique

Tôi cho rằng perl nhanh hơn sed, nhưng sed có phần khó hiểu hơn, hoặc yêu cầu ít hơn một đường cong học tập ban đầu.
Dani_l

1
Hãy xem, bây giờ tôi đã nói ngược lại - bạn có thể (gần như) viết sedvào perl, nhưng sau này cũng cho phép bạn viết nhiều kịch bản dài dòng hơn.
Sobrique

0

Nếu các văn bản mới và cũ có cùng độ dài, bạn có thể tìm kiếm vào tệp và chỉ viết các byte đã thay đổi, thay vì sao chép toàn bộ tệp. Nếu không, bạn bị mắc kẹt trong việc di chuyển nhiều dữ liệu.

Lưu ý: điều này là khó khăn và liên quan đến việc viết mã tùy chỉnh.

Xem trang hướng dẫn để biết nếu bạn đang làm việc trong C hoặc C ++ hoặc trình bao bọc ngôn ngữ ưa thích của bạn cho các cuộc gọi hệ thống tìm kiếm và viết.

Nếu bạn khăng khăng chỉ sử dụng dòng lệnh và bạn có thể nhận được các byte của văn bản, bạn có thể viết văn bản thay thế tại chỗ bằng các lệnh "dd" được viết cẩn thận.

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.