so sánh hai cột của các tệp khác nhau và in nếu nó khớp


16

Tôi đang sử dụng Solaris 10 và vì vậy các tùy chọn grep liên quan đến -f không hoạt động.

Tôi có hai tệp được phân tách bằng ống:

tập tin1:

abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|

tập 2:

abc|123|
kumar|pki|
cab|234

Tôi muốn so sánh hai cột đầu tiên của tệp2 với tệp1 (tìm kiếm toàn bộ nội dung của tệp1 trong hai cột đầu tiên) nếu chúng khớp với dòng in của tệp1. Sau đó tìm kiếm dòng thứ hai của tệp 2 và cứ thế.

Đầu ra dự kiến:

abc|123|BNY|apple|
cab|234|cyx|orange|

Các tập tin tôi có rất lớn, chứa khoảng 400.000 dòng, vì vậy tôi muốn thực hiện nhanh chóng.


Tôi đã xóa các khoảng trắng hàng đầu khỏi các ví dụ của bạn, nếu bạn muốn, vui lòng cuộn lại phần chỉnh sửa. Hãy nhớ rằng không gian là đáng kể, bạn chỉ nên có chúng nếu chúng tồn tại trong các tập tin thực tế của bạn.
terdon

Hãy thử sử dụng phiên bản GNU của grep/usr/sfw/bin/ggrep. stackoverflow.com/questions/15259882/
Mạnh

Câu trả lời:


21

Đây là những gì awk được thiết kế cho:

$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|

Giải trình

  • -F'|': đặt dấu phân cách trường thành |.
  • NR==FNR: NR là số dòng đầu vào hiện tại và FNR số dòng của tệp hiện tại. Cả hai sẽ chỉ bằng nhau trong khi tập tin 1 đang được đọc.
  • c[$1$2]++; next: nếu đây là tệp đầu tiên, hãy lưu hai trường đầu tiên trong cmảng. Sau đó, bỏ qua dòng tiếp theo để điều này chỉ được áp dụng trên tệp 1.

  • c[$1$2]>0: khối khác sẽ chỉ được thực thi nếu đây là tệp thứ hai để chúng tôi kiểm tra xem các trường 1 và 2 của tệp này đã được nhìn thấy chưa ( c[$1$2]>0) và nếu chúng đã được, chúng tôi sẽ in dòng. Trong awk, hành động mặc định là in dòng để nếu c[$1$2]>0đúng, dòng sẽ được in.


Ngoài ra, vì bạn đã gắn thẻ với Perl:

perl -e 'open(A, "file2"); while(<A>){/.+?\|[^|]+/ && $k{$&}++};
         while(<>){/.+?\|[^|]+/ && do{print if defined($k{$&})}}' file1

Giải trình

Dòng đầu tiên sẽ mở file2, đọc mọi thứ cho đến lần thứ 2 |( .+?\|[^|]+) và lưu lại (đó $&là kết quả của toán tử khớp cuối cùng) trong %khàm băm.

Dòng thứ hai xử lý tệp1, sử dụng cùng một biểu thức chính để trích xuất hai cột thứ nhất và in dòng nếu các cột đó được xác định trong %khàm băm.


Cả hai cách tiếp cận trên sẽ cần giữ 2 cột đầu tiên của tệp2 trong bộ nhớ. Đó không phải là vấn đề nếu bạn chỉ có vài trăm nghìn dòng nhưng nếu có, bạn có thể làm một cái gì đó như

cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done

Nhưng điều đó sẽ chậm hơn.


Nhưng điều này sẽ không tải tất cả (hai cột đầu tiên) file2vào bộ nhớ?
Joseph R.

@terdon: awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0'là phiên bản ngắn hơn.
cuonglm

nó không hoạt động ..
user68365

@ user68365: Có file2hàng trùng lặp không?
cuonglm

KHÔNG, nó không có bất kỳ hàng trùng lặp nào
user68365

1

tôi nghĩ

grep -Ff file2 file1

là những gì bạn đang tìm kiếm. Nó sẽ hiệu quả, nhưng tôi không chắc nó sẽ chính xác như bạn muốn. Nếu abc|123(ví dụ) được tìm thấy trong một dòng file1trong các cột khác nhau, dòng đó cũng sẽ được in. Nếu bạn có thể đảm bảo rằng điều này sẽ không bao giờ xảy ra, dòng trên sẽ hoạt động.


Grep sẽ không đủ, vì abc | 123 có thể có mặt ở đâu đó trong tập tin thứ. Hơn nữa, tôi đang sử dụng solaris 10 và tôi cũng không thể sử dụng tùy chọn grep đó.
dùng68365

2
@ user68365 vui lòng làm rõ tất cả điều này trong câu hỏi của bạn. Bạn cần cho chúng tôi biết hệ điều hành của bạn và chỉ định rằng bạn chỉ muốn khớp 2 cột đầu tiên.
terdon

1

Nếu bạn muốn nghĩ vấn đề theo cách SQL, thì bạn chắc chắn nên thử một công cụ có tên ' q ':

$ q -d '|' "select f1.* from file1 f1 join file2 f2 on (f1.c1 = f2.c1 and f1.c2 = f2.c2)"

Rõ ràng và dễ hiểu hơn nếu bạn quen thuộc với truy vấn SQL.


Cảm ơn bạn cho một trong những giải pháp khó hiểu nhất, cho đến nay. Đó là điều tôi muốn. Nhưng tôi gặp một số khó khăn khi tìm "công cụ q" này
Rolf

Công cụ rất hữu ích.
ghilesZ

0
$  sed 's/^/\^/' 2.txt > temp.txt ; grep 1.txt -f temp.txt
abc|123|BNY|apple|
cab|234|cyx|orange|

1
Như tôi đã chỉnh sửa và đề cập trong câu hỏi, các tùy chọn grep -f không hoạt động trong hệ thống của tôi
user68365

Solaris 10 có lõi-gils trong / usr / sfw / bin Sử dụng / usr / sfw / bin / sed và / usr / sfw / bin / grep
mr_tron
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.