Đâ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 c
mả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 %k
hà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 %k
hà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.