Tìm ID trong một tệp không nằm trong tệp khác


9

Tôi có hai tệp:

abc.txt

abcd
xyz
pqrs

mno.txt

zzon
mkno
abcd
  • Tôi muốn kiểm tra xem "abcd" có trong tập tin mno.txt không .
  • Không cần thiết nếu "abcd" là lần đầu tiên trong abc.txt , thì nó cũng sẽ đầu tiên trong mno.txt .
  • Có hàng ngàn id như vậy trong cả hai tập tin.
  • Tôi cũng muốn kiểm tra xem có bao nhiêu id không có trong mno.txt trong abc.txt .

Tôi có thể làm cái này như thế nào ?

Câu trả lời:


19

Nếu mục tiêu của bạn là tìm các dòng chung hoặc không phổ biến, commđó sẽ là lệnh truy cập của tôi ở đây.

Nó so sánh hai tệp và hiển thị ba dòng của dònginin là dòng duy nhất cho tệp 1, các dòng duy nhất cho tệp 2 và các dòng xuất hiện trong cả hai tệp, tương ứng. Bạn cũng có thể truyền cờ cho nó để chặn bất kỳ đầu ra nào. Ví dụ, comm -1 file1 file2sẽ chặn cột đầu tiên, những thứ duy nhất cho tệp1. comm -12 file1 file2sẽ chỉ hiển thị những thứ trong cả hai tập tin.

Có một cảnh báo lớn: đầu vào phải được sắp xếp. Chúng ta có thể làm việc xung quanh điều này.

Điều này sẽ cho bạn thấy mọi thứ trong abc không có trong mno:

comm -23 <(sort abc.txt) <(sort mno.txt)

Và bạn có thể dẫn nó vào wc -lđể có được một số lượng.


Lý do tôi đi cùng commlà một khi các tệp được sắp xếp, việc so sánh song song thực sự đơn giản. Nếu bạn đang đối phó với hàng triệu trong số này, điều đó sẽ tạo ra sự khác biệt.

Điều này có thể được chứng minh với một vài tệp giả. Tôi có một máy tính khá nhanh vì vậy để cho thấy sự khác biệt giữa các phương pháp, tôi cần một bộ mẫu voi ma mút. Tôi đã đạt tới 10 triệu chuỗi 10 ký tự cho mỗi tệp.

$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > abc.txt
$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > mno.txt

$ time comm -23 <(sort abc.txt) <(sort mno.txt) | wc -l
... 0m10.653s

$ time grep -Fcxv -f abc.txt mno.txt
... 0m23.920s

$ time grep -Fcwv -f abc.txt mno.txt
... 0m40.313s

$ time awk 'NR==FNR{a[$0]++};NR!=FNR && a[$0]' abc.txt  mno.txt | wc -l
... 0m12.161s

Việc sắp xếp là những gì chiếm phần lớn thời gian trong tôi. Nếu chúng tôi giả vờ rằng abc.txt là tĩnh, chúng tôi có thể sắp xếp trước nó và điều đó làm cho các so sánh trong tương lai nhanh hơn nhiều:

$ sort abc.txt abc-sorted.txt
$ time comm -23 abc-sorted.txt <(sort mno.txt) | wc -l
... 0m7.426s

Bạn có thể nhìn vào những thứ này và xem xét một vài giây không liên quan nhưng tôi phải nhấn mạnh rằng những thứ này đang chạy trên một máy cao cấp. Nếu bạn muốn thực hiện điều này trên (ví dụ) Raspberry Pi 3, bạn sẽ xem xét các vòng quay chậm hơn nhiều và sự khác biệt sẽ tăng lên đến mức nó thực sự quan trọng.


7

để có được một danh sách:

grep -Fwf abc.txt mno.txt

nó cung cấp cho bạn một cái gì đó tương tự như:

abcd
abcd
zef

nếu bạn muốn chỉ có một danh sách duy nhất thì hãy sử dụng nó như sau:

grep -Fwf abc.txt mno.txt | sort | uniq

và để có được số lượng:

grep -Fcwv -f abc.txt mno.txt

  • -F có nghĩa là: giải thích MẪU như một danh sách các chuỗi cố định thay vì các biểu thức thông thường.
  • -fcó được các mẫu từ TẬP_TIN abc.txt.
  • chúng tôi xem xét mno.txtcác mẫu
  • -c Đếm số lượng trận đấu
  • -wChỉ tìm "toàn bộ từ": chuỗi con phù hợp phải ở đầu dòng hoặc đứng trước ký tự cấu thành không từ. Tương tự, nó phải ở cuối dòng hoặc theo sau là một ký tự cấu thành không từ. Các ký tự cấu thành từ là chữ cái, chữ số và dấu gạch dưới.
  • -v Đảo ngược tìm kiếm

1
Nếu OP muốn một số các phi diêm, không nên có được nhiều hơn như grep -cxvFf abc.txt mno.txt?
Steeldo

Chỉ cần nhìn thấy nó: D ... bạn luôn ở đây để cứu tôi: D
Ravexina

FYI fgrep, egrepnhững người thay thế được cho là không tán thành (ủng hộ grep -F, grep -E- mặc dù tôi không chắc ai tin rằng họ sẽ biến mất
Steeldo

Có cần thiết phải sử dụng -xkhi sử dụng -F?
Ravexina

1
Nó phụ thuộc vào những gì OP muốn tính chính xác - ví dụ: nếu mno.txt chứa abcdefthì đó có nên được tính là khớp hay không khớp abcd?
Steeldo

3

Chúng ta có thể sử dụng awk để thực hiện công việc bằng cách chuyển hai tệp, đầu tiên là tệp mẫu, sau đó là tệp chúng ta muốn kiểm tra. Khi chúng ta đọc tệp đầu tiên, chúng ta biết rằng NR==FNRvà tại thời điểm đó chúng ta có thể đọc các dòng thành mảng. Khi NR!=FNRchúng tôi kiểm tra nếu mảng cho dòng như vậy được thiết lập.

$ cat abc.txt                                                      
abcd
xyz
pqrs
$ cat mno.txt                                                      
zzon
xyz
mkno
abcd
$ awk 'NR==FNR{a[$0]++};NR!=FNR && a[$0]' abc.txt  mno.txt         
xyz
abcd

Ngược lại, chúng ta có thể phủ định mẫu để in những dòng không có trong đó abc.txt

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt       
zzon
mkno

Và nếu chúng tôi muốn in số lượng những người chúng tôi có thể sử dụng sortwc:

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt | sort -u | wc -l         
2

Tôi nghĩ rằng bạn có nó sai cách xung quanh. Theo như tôi hiểu câu hỏi, OP muốn tính (kích thước) sự khác biệt đã đặt của abc.txt- mno.txtđó là {xyz, pqrs}.
David Foerster

2

Nếu một trong hai danh sách từ chưa được sắp xếp, sẽ nhanh hơn khi sử dụng cấu trúc dữ liệu được thiết lập hiệu quả để ghi nhớ các từ phổ biến.

Con trăn

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as minuend_file:
    minuend = frozenset(map(str.rstrip, minuend_file))
with open(sys.argv[2]) as subtrahend_file:
    subtrahend = frozenset(map(str.rstrip, subtrahend_file))

difference = minuend - subtrahend
#print(*difference, sep='\n') # This prints the content of the set difference
print(len(difference)) # This prints the magnitude of the set difference

Sử dụng:

python3 set-difference.py abc.txt mno.txt

Python (hiệu quả hơn)

Nếu bạn muốn tiết kiệm một chút bộ nhớ để lưu trữ trung gian và thời gian chạy, bạn có thể sử dụng chương trình hơi khó hiểu này:

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as minuend_file:
    minuend = set(map(str.rstrip, minuend_file))
with open(sys.argv[2]) as subtrahend_file:
    subtrahend = map(str.rstrip, subtrahend_file)
    minuend.difference_update(subtrahend)
    difference = minuend
    del minuend

#print(*difference, sep='\n') # This prints the content of the set difference
print(len(difference)) # This prints the magnitude of the set difference

Hiệu suất

Cho abc.txtmno.txtvới 1 mio dòng chưa được sắp xếp gồm 10 ký tự chữ số ASCII ngẫu nhiên mỗi dòng (xem câu trả lời của Oli để thiết lập):

$ time python3 set-difference.py abc.txt mno.txt
user    0m10.453s

so với

$ export LC_COLLATE=C
$ time sort abc.txt > abc_sorted.txt
user    0m10.652s
$ time sort mno.txt > mno_sorted.txt
user    0m10.767s
$ time comm -23 abc_sorted.txt mno_sorted.txt | wc -l
9989882
user    0m1.600s

tổng cộng: 23 giây

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.