In các dòng từ một tập tin nếu một phần của chúng xuất hiện trong một tập tin khác. Cả hai tệp dài hàng triệu dòng


7

Tôi có hai tập tin, hãy gọi cho họ 123.txt789.txt. 123.txtdài 2,5 triệu dòng và dài 789.txt65 triệu dòng. Có cách nào để sử dụng grephoặc tương tự để giữ bất kỳ dòng 789.txtnào có chứa các dòng từ123.txt?

Sẽ có tối đa một bản sao trên mỗi dòng 789.txtvà văn bản trùng lặp sẽ ở đầu dòng. Tôi hoàn toàn bế tắc về điều này và không thể tìm thấy bất kỳ thông tin nào trên mạng, vì vậy tôi thực sự không có gì để bắt đầu. Nó sẽ chạy trên một máy chủ, vì vậy tôi không ngại mất một lúc (mà tôi biết nó sẽ)

  • 123.txt:

    hxxp://www.a.com
    hxxp://www.b.com
    hxxp://www.c.com
    
  • 789.txt:

    hxxp://www.a.com/kgjdk-jgjg/
    hxxp://www.b.com/gsjahk123/
    hxxp://www.c.com/abc.txt
    hxxp://www.d.com/sahgsj/
    
  • Sản phẩm chất lượng:

    hxxp://www.a.com/kgjdk-jgjg/
    hxxp://www.b.com/gsjahk123/
    hxxp://www.c.com/abc.txt
    

Câu trả lời:


13

Bạn có thể làm điều này rất dễ dàng bằng cách sử dụng grep:

$ grep -Ff 123.txt 789.txt
http://www.a.com/kgjdk-jgjg/ 
http://www.b.com/gsjahk123/ 
http://www.c.com/abc.txt 

Lệnh trên sẽ in tất cả các dòng từ tệp 789.txtcó chứa bất kỳ dòng nào từ đó 123.txt. -F có nghĩa là "đọc các mẫu để tìm kiếm từ tệp này" và -F bảo grep coi các mẫu tìm kiếm là các chuỗi và không phải là các biểu thức chính quy mặc định của nó.

Điều này sẽ không hoạt động nếu các dòng 123.txtchứa khoảng trắng ở cuối, grepsẽ coi các khoảng trắng là một phần của mẫu để tìm kiếm sẽ không khớp nếu nó xuất hiện trong một từ. Ví dụ: mẫu foo (lưu ý không gian dấu) sẽ không khớp foobar. Để xóa dấu cách từ tệp của bạn, hãy chạy lệnh này:

$ sed 's/ *$//' 123.txt > new_file

Sau đó sử dụng new_fileđể grep:

$ grep -Ff new_file 789.txt

Bạn cũng có thể làm điều này mà không cần tệp mới, sử dụng icờ:

$ sed -i.bak 's/ *$//' 123.txt

Điều này sẽ thay đổi tập tin 123.txtvà giữ một bản sao của bản gốc được gọi 123.txt.bak.

(Lưu ý rằng dạng -icờ này để sedgiả sử bạn có GNU sed; để sedsử dụng BSD -i .bakvới khoảng trắng ở giữa.)


Tôi không nghĩ rằng tùy chọn đầu tiên sẽ hoạt động, bất kể trường hợp của OP: nó sẽ in các dòng 123.txtkhông xuất hiện 789.txtcũng như các dòng trong 789.txtđó 123.txt(chúng sẽ chỉ được in một lần, nhưng dù sao cũng được in).
Joseph R.

3
@JosephR. bạn hoàn toàn đúng, xấu của tôi. Tôi đã loại bỏ đề nghị đó. Cảm ơn đã chỉ ra điều đó.
terdon

Xin chào, cảm ơn rất nhiều :) nó gần như đang hoạt động, nhưng có hai điều nhỏ - đó là giữ những cái phù hợp với tập tin khác, và phần khớp với perl dường như không hoạt động trong bài kiểm tra tôi chạy, có vẻ là bởi vì tất cả các dòng của tôi không có bất kỳ khoảng trống trong chúng. Tôi xin lỗi vì sự nũng nịu, kỹ năng perl của tôi không được tốt lắm.
Joe

@Joe không thành vấn đề. Bạn có thể thêm một số ví dụ đầu vào cho câu hỏi của bạn để tôi có thể hiểu rõ hơn về những gì bạn cần? Cũng bao gồm đầu ra mong muốn của bạn.
terdon

Xin chào, cảm ơn rất nhiều, điều đó gần như làm việc với tôi, tuy nhiên tôi dường như chỉ nhận được các trận đấu đầy đủ chứ không phải là một phần trận đấu.
Joe

4

Nếu các tệp như trong ví dụ của bạn được sắp xếp và luôn tuân theo mẫu đó, bạn có thể viết nó:

join -t/ -1 3 -2 3 123.txt 789.txt |
  sed -n 's,\([^/]*/\)\([^/]*://\)\2,\2\1,p'

Đó sẽ là hiệu quả nhất.

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.