Kiểm tra xem tất cả các dòng của tập tin xảy ra trong các tập tin khác nhau


14

Tôi có hai tệp: file1 với khoảng 10 000 dòng và file2 với vài trăm dòng. Tôi muốn kiểm tra xem tất cả các dòng của file2 có xảy ra trong file1 không. Đó là: dòng ℓ ∈ file2: ℓ file1

Nếu ai đó không biết những ký hiệu này có nghĩa là gì hoặc "kiểm tra xem tất cả các dòng của tệp 2 xảy ra trong tệp 1" có nghĩa là gì: Một số dòng tương đương trong một trong hai tệp không ảnh hưởng đến việc kiểm tra có trả về các yêu cầu đó hay không.

Làm thế nào để tôi làm điều này?


2
Có thể những tập tin có dòng trùng lặp? Nếu file2chứa 2 dòng A, bạn có cần file1chứa ít nhất 2 dòng Akhông?
Stéphane Chazelas

2
@ StéphaneChazelas Tất cả các dòng (trong cả hai tệp) được đảm bảo là duy nhất.
UTF-8

1
@ UTF-8 Đó sẽ là một chi tiết quan trọng để chỉnh sửa câu hỏi của bạn.
David Z

2
@DavidZ Không còn nữa vì các câu trả lời hiện tại không dựa vào sự đảm bảo đó. Vì vậy, bằng cách chỉnh sửa câu hỏi ngay bây giờ, tôi sẽ giảm phạm vi câu trả lời rõ ràng.
UTF-8

@ UTF-8 Tôi cho là như vậy, mặc dù câu hỏi hơi mơ hồ nếu không có nó, ví dụ nếu một dòng nhất định xảy ra 5 lần trong tệp 2, thì dòng đó cũng phải xảy ra 5 lần trong tệp1 (trái ngược với chỉ một lần)? Nếu bạn có yêu cầu đó, nó không giống như bất kỳ câu trả lời hiện có nào sẽ hoạt động, vì vậy tôi khuyên bạn nên ít nhất chỉnh sửa trong một cái gì đó làm rõ rằng đó không phải là ý bạn.
David Z

Câu trả lời:


18
comm -13 <(sort -u file_1) <(sort -u file_2)

Lệnh này sẽ xuất các dòng duy nhất cho file_2. Vì vậy, nếu đầu ra trống, thì tất cả các file_2dòng được chứa trong file_1.

Từ người đàn ông của comm:

   With  no  options,  produce  three-column  output.  Column one contains
   lines unique to FILE1, column two contains lines unique to  FILE2,  and
   column three contains lines common to both files.

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

@don_crissti Đúng. Đã sửa: -utùy chọn được thêm vào sortlệnh. Bây giờ, chỉ còn lại các dòng duy nhất trong cả hai tệp được sắp xếp.
MiniMax

Giải pháp đơn giản! Cú pháp này có áp dụng cho bất kỳ chương trình nào mong đợi các tệp không? Tôi luôn nghĩ rằng <đường ống vào stdin. Liệu thuật ngữ khung thay đổi điều này?
UTF-8

2
@ UTF-8 Nó được gọi là quá trình thay thế . Bạn có thể đọc ở đây về nó. Và vâng, nó hoạt động như một tệp tạm thời, vì vậy nó có thể được sử dụng thay vì các tệp thực trong bất kỳ chương trình nào, dự kiến ​​các tệp.
MiniMax

Nếu đây là việc bạn thường xuyên làm, bạn có thể muốn lưu trữ file_1ở dạng đã định sẵn. Tiết kiệm cả gõ và thời gian.
Stig Hemmer

7
@minimax Nhận xét tốt ngoại trừ "bất kỳ". Thay thế quá trình, trong khi tuyệt vời, không thể được sử dụng trong mọi trường hợp, bởi vì "tệp" kết quả là luồng và không phải là tệp thực. Điều này có nghĩa là chúng không "có thể tìm kiếm" như một tệp bình thường và chỉ có thể được sử dụng khi chương trình đọc tệp bình thường ngay từ đầu chứ không phải khi chương trình sử dụng một số chức năng chỉ có tệp như tìm kiếm đến một điểm cụ thể hoặc tua lại để bắt đầu lại từ đầu. Hạnh phúc, hầu hết các chương trình chỉ đơn giản là đọc () tệp của họ và vì vậy quá trình thay thế hoạt động với hầu hết các chương trình, nhưng không phải là "bất kỳ" chương trình nào.
Luật29

7
[ $(grep -cxFf file2 <(sort -u file1)) = $(sort -u file2 | wc -l) ] && 
  echo all there || 
  echo some missing

Nếu số lượng trùng khớp từ tệp2 trong (các dòng duy nhất) của tệp1 giống với số lượng các dòng duy nhất trong tệp2, thì tất cả chúng đều ở đó; mặt khác, họ không.


5

Sử dụng GNU awk, nơi nó hỗ trợ length(array)tính năng cụ thể (và một số awktriển khai khác có thể hỗ trợ) và không bắt buộc nếu các tệp được sắp xếp.

gawk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{print (!length(seen))?"Matched":"Not Matched"}' file2 file1

Đây là đọc file2 thành một mảng được gọi seenvới khóa là toàn bộ dòng của tệp2 .

Sau đó đọc file1 và cho mỗi dòng nếu khớp với các dòng trong mảng nhìn thấy rồi xóa khóa đó.

Cuối cùng, nếu mảng trống có nghĩa là tất cả các dòng trong tệp 2 tồn tại trong tệp1 và sẽ in Matched, nếu không sẽ hiển thị Not Matched.


Đối với sự tương thích trong tất cả các awkthực hiện.

awk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{for(x in seen);print (!x)?"Matched":"Not Matched"}' file2 file1

Để bỏ qua các dòng trống / hoặc các dòng có khoảng trắng chỉ trong tệp 2 , bạn sẽ cần thêm NFvào điều kiện NR==FNR && NF {...để bỏ qua việc đọc chúng vào mảng.


length(array)là AFAIK chỉ gawk; nó chắc chắn không phải là POSIX.
dave_thndry_085

@ dave_thndry_085 Đúng, tôi đã cập nhật câu trả lời của mình. thanks
αғsнιη

3

Sử dụng commbạn có thể tìm thấy các dòng phổ biến trong cả hai tập tin.

comm -12 file1 file2

Hãy xem man commđể biết thêm chi tiết


Chính xác, nó trả về các dòng chung trong cả hai tệp, nhưng điều này không cung cấp câu trả lời cho Q của OP trong đó nếu bạn có một dòng trong tệp2 không thoát trong tệp1, vì vậy tất cả các dòng của tệp 2 không tồn tại trong tệp1.
αsнι

1
các tập tin nên được sắp xếp. Từ người đàn ông " comm- so sánh hai tập tin được sắp xếp theo từng dòng".
MiniMax

@MiniMax đã đúng. Điều này không hoạt động. Câu trả lời khác sử dụng commcó chứa một giải pháp rõ ràng là không chính xác. Khi tôi chạy lệnh của bạn, tôi nhận được cảnh báo rằng các tệp không theo thứ tự được sắp xếp và rất nhiều dòng chắc chắn có trong cả hai tệp.
UTF-8

3
diff -q <(sort -u file2) <(grep -Fxf file2 file1 | sort -u)

sẽ không tạo ra đầu ra nếu file1chứa tất cả các dòng vào file2và thoát với trạng thái 0, nếu không nó sẽ in một cái gì đó như

Files /proc/self/fd/11 and /proc/self/fd/12 differ

và thoát với trạng thái 1


2

Sử dụng chương trình Python:

#!/usr/bin/env python3
import sys

def open_arg(path):
    return sys.stdin if path == '-' else open(path)

def strip_linebreak(s):
    return s[:-1] if s.endswith('\n') else s

with open_arg(sys.argv[1]) as pattern_file:
    patterns = set(map(strip_linebreak, pattern_file))

with open_arg(sys.argv[2]) as dataset_file:
    for l in map(strip_linebreak, dataset_file):
        patterns.remove(l)
        if not patterns:
            break

sys.exit(int(bool(patterns)))

Sử dụng:

python3 contains-all.py file2 file1

Trạng thái thoát chương trình cho biết liệu tất cả các mẫu của tệp 2 có khớp hay không:

  • 0 (thành công) có nghĩa là tất cả các mẫu đã được khớp.
  • 1 (thất bại) có nghĩa là một số mẫu không khớp.

Để truy vấn trạng thái thoát trong một vỏ (script) bạn có thể sử dụng các $?biến đặc biệt hoặc biểu thức khác mà đánh giá trạng thái thoát lệnh, ví dụ như các nhà khai thác ngắn mạch &&||và các biểu thức có điều kiện như ifhay while. Thí dụ:

if python3 compare-all.py file2 file1 && some-other --condition; then
    # do stuff
fi

1

combinetừ moreutils sẽ hiển thị cho bạn tất cả các dòng file2không có trong file1:

combine file2 not file1

Sau đó, bạn có thể đếm số lượng dòng bằng cách đặt nó vào wc -l, như:

if [ $(combine file2 not file1 | wc -l) != 0 ]; then
  echo "lines missing"
else
  echo "You're fine"
fi
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.