Có một công cụ để có được các dòng trong một tập tin mà không phải trong một tập tin khác?


110

Có công cụ nào có thể nhận được dòng mà tập tin A chứa, nhưng tập tin B không? Tôi có thể tạo một kịch bản đơn giản với, ví dụ như perl, nhưng nếu một cái gì đó như thế đã tồn tại, tôi sẽ tiết kiệm thời gian của mình kể từ bây giờ.



Câu trả lời:


159

Đúng. Công grepcụ tiêu chuẩn để tìm kiếm tệp cho chuỗi văn bản có thể được sử dụng để trừ tất cả các dòng trong một tệp từ tệp khác.

grep -F -x -v -f fileB fileA

Điều này hoạt động bằng cách sử dụng mỗi dòng trong tệpB như một mẫu ( -f fileB) và coi nó như một chuỗi đơn giản để khớp (không phải là biểu thức chính quy thông thường) ( -F). Bạn buộc trận đấu diễn ra trên toàn bộ dòng ( -x) và chỉ in ra những dòng không khớp ( -v). Do đó, bạn đang in các dòng trong tệpA không chứa cùng dữ liệu với bất kỳ dòng nào trong tệpB.

Nhược điểm của giải pháp này là nó không tính đến thứ tự dòng và nếu đầu vào của bạn có các dòng trùng lặp ở những nơi khác nhau, bạn có thể không nhận được những gì bạn mong đợi. Giải pháp cho điều đó là sử dụng một công cụ so sánh thực sự như diff. Bạn có thể làm điều này bằng cách tạo một tệp diff với giá trị ngữ cảnh ở 100% các dòng trong tệp, sau đó phân tích cú pháp cho các dòng sẽ bị xóa nếu chuyển đổi tệp A thành tệp B. (Lưu ý lệnh này cũng loại bỏ diff định dạng sau khi nó nhận được đúng dòng.)

diff -U $(wc -l < fileA) fileA fileB | sed -n 's/^-//p' > fileC

@ inderpreet99 -uĐối số chữ thường thực sự lấy tham số của một số miễn là nó không được theo sau bởi khoảng trắng . Ưu điểm của cách tôi đã có trước đây là nó sẽ hoạt động có hoặc không có giá trị, vì vậy bạn có thể sử dụng một cái gì đó trong thói quen lệnh phụ mà trả về không xuất ra. Chữ hoa '-U' mặt khác yêu cầu một đối số.
Caleb

hãy cẩn thận, grep -f là O (N ^ 2) Tôi tin rằng: stackoverflow.com/questions/4780203/
triệt

1
các diffđường ống làm việc một điều trị cảm ơn.
Felipe Alvarez

Để giải quyết vấn đề sắp xếp, bạn có thể sử dụng thay thế quy trình trong lệnh để xử lý từng tệp trước khi grepcần. Ví dụ:grep -F -x -v -f <(sort fileB) <(sort fileA)
Tony Cesaro

@TonyCesaro Điều đó sẽ hoạt động nếu tập dữ liệu của bạn không theo thứ tự cụ thể và các bản sao không cần phải tính đến. Ưu điểm của việc sử dụng difflà vị trí trong tệp được tính đến.
Caleb

57

Câu trả lời phụ thuộc rất nhiều vào loại và định dạng của các tệp bạn đang so sánh.

Nếu các tệp bạn đang so sánh là các tệp văn bản được sắp xếp, thì công cụ GNU được viết bởi Richard Stallman và Davide McKenzie được gọi commcó thể thực hiện quá trình lọc mà bạn đang theo dõi. Nó là một phần của coreutils.

Thí dụ

Giả sử bạn có 2 tệp sau:

$ cat a
1
2
3
4
5

$ cat b
1
2
3
4
5
6

Các dòng trong tệp bkhông có trong tệp a:

$ comm <(sort a) <(sort b) -3
    6

1
+1 để đề cập comm; thật không may, commyêu cầu các tệp được sắp xếp
Arcege

11
Vì vậy, sắp xếp chúng? comm <(sort a) <(sort b) -1 -2
Sirex

Đây là một số cú pháp kỳ lạ. <()? Nó hoạt động và tôi hiểu nó, nhưng có một cái tên cho sự kỳ lạ này?
mlissner

2
@mlissner <()còn được gọi là quá trình thay thế .
miku

1
commban đầu được viết vào khoảng năm 1973 bởi một người nào đó tại Bell Labs, không phải rms. Bạn đang đề cập đến việc triển khai GNU mà sau này rất nhiều. Đã có rất nhiều triển khai khác nhau của các tiện ích Unix trong những năm qua.
Stéphane Chazelas

32

từ stackoverflow ...

comm -23 file1 file2

-23 loại bỏ các dòng trong cả hai tệp hoặc chỉ trong tệp 2. Các tệp phải được sắp xếp (chúng nằm trong ví dụ của bạn) nhưng nếu không, hãy chuyển chúng qua sắp xếp trước ...

Xem trang người đàn ông ở đây


Điều này không làm việc cho tôi, vì một lý do ...
Jan

@Jan các tập tin của bạn được sắp xếp? Làm thế nào bạn sắp xếp chúng?
JJS

8

Các phương thức grep và comm (with sort) mất nhiều thời gian trên các tệp lớn. SiegeX và ghostdog74 đã chia sẻ hai phương pháp awk tuyệt vời để trích xuất các dòng duy nhất cho một trong hai tệp trên Stack Overflow:

$ awk 'FNR==NR{a[$0]++}FNR!=NR && !a[$0]{print}' file1 file2

$ awk 'FNR==NR{a[$0]++;next}(!($0 in a))' file1 file2

2
Nếu bạn đang làm điều này với các tệp lớn, thì các ràng buộc về bộ nhớ của việc tải một tệp lớn vào một mảng kết hợp sẽ bị cấm.
Charles Duffy

4

Nếu các tệp lớn và bạn không có thứ tự tùy chỉnh cho các mục nhập của mình, grep sẽ mất quá nhiều thời gian. Một sự thay thế nhanh chóng sẽ là

sort file1 > 1 
sort file2 > 2 
diff 1 2 | grep "\>" | sed -e 's/> //'

[file2-file1 kết quả để sàng lọc, đường ống đến tập tin, v.v.]

Thay đổi >để <có được phép trừ ngược lại.rm 1 2


2

Bạn cũng có thể xem xét vimdiff, nó làm nổi bật sự khác biệt giữa các tệp trong trình chỉnh sửa vim


1
Nhưng có cách nào dễ dàng để tự động thực hiện phép trừ trong Vimdiff không?
Kazark
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.