So sánh hai tệp với cột đầu tiên và xóa hàng trùng lặp khỏi tệp thứ 2 trong tập lệnh shell


9

Tôi sẽ hỏi câu hỏi của tôi với một ví dụ. Tôi có 2 tệp:

Tệp số 1:

118D FC300_R5_TP  FX.B      32775       2112   6       2038   6       2112   0
118E FC300_R5_TP  FX.B      32775       2136   7       2065   6       2136   0
118F FC300_R5_TP  FX.B      32775       2124   6       2064   6       2124   0
1190 FC300_R5_TP  FX.B     819210     814632  99     814609  99     814632   0
1191 FC300_R5_TP  FX.B     819210     104100  13     103714  13     104100   0
1192 FC300_R5_TP  FX.B    1638420    1609476  98    1609402  98    1609476   0
1196 FC300_R5_TP  FX.B    1638420    1638432 100    1638379 100    1638432   0
119A FC300_R5_TP  FX.B    3276840    3271776 100    3271698 100    3271776   0
119E FC300_R5_TP  FX.B    3276840    3264120 100    3264034 100    3264120   0
11A2 FC300_R5_TP  FX.B    3276840    2328648  71    2328546  71    2328648   0
11A6 FC300_R5_TP  FX.B    3276840    2328444  71    2328355  71    2328444   0
11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0

Tệp số 2:

11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Sản phẩm chất lượng

Tệp số 3:

0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Tôi muốn so sánh tệp 1 và tệp 2 bằng các cột đầu tiên của chúng và xóa toàn bộ dòng hoặc hàng khỏi tệp 2 nơi chúng khớp với tệp 1. Tôi cũng muốn lưu kết quả vào tệp thứ 3, tệp số 3.

Câu trả lời:


10

Bạn có thể sử dụng awkcho việc này:

awk 'FNR==NR{a[$1];next};!($1 in a)' file1 file2 > file3

Giải trình:

  • FNR == NR: Thử nghiệm này là đúng khi số lượng hồ sơ bằng với số lượng hồ sơ trong tệp. Điều này chỉ đúng với tệp đầu tiên, đối với tệp thứ hai NRsẽ bằng số dòng của tệp1 + FNR.

  • a[$1]: Tạo một chỉ mục phần tử mảng của trường đầu tiên của tệp1.

  • next: bỏ qua bản ghi tiếp theo để không xử lý nữa trên tệp1.

  • !($1 in a): Xem trường đầu tiên ($ 1) có trong mảng không, tức là trong tệp 1 và in toàn bộ dòng (sang tệp3).

Dựa trên một trong những ví dụ từ wiki #awk .


Câu trả lời hoàn hảo!!!
mtk

8
export LC_ALL=C
comm -13 <(sort f1) <(sort  f2)

Sẽ báo cáo các dòng chỉ trong f2.

export LC_ALL=C
join -v2 <(sort f1) <(sort f2)

Sẽ báo cáo các dòng f2có trường đầu tiên không được tìm thấy là trường đầu tiên trong bất kỳ dòng nào f1.

(bạn cần một trình bao với sự hỗ trợ để thay thế quá trình như ksh93, zshhoặc bash).


2

Chỉ để giải trí đây là một giải pháp trong Perl:

#!/usr/bin/perl

# create names lookup table from first file
my %names;
while (<>) {
    (my $col1)= split / /, $_;
    $names{$col1} = 1;
    last if eof;
}

# scan second file
while (<>) {
    print if /^(\S+).*/ && not $names{$1};
}

Thí dụ

$ ./showdiffs.pl file1  file2
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Chi tiết

Giải pháp Perl ở trên bao gồm 2 vòng. Vòng lặp đầu tiên đọc tất cả các dòng từ file1và tạo ra một hàm băm, %namestrong đó mỗi cột mà chúng tôi xác định được thêm vào.

$names{11AA} = 1;

whileVòng lặp thứ 2 sau đó chạy qua tệp thứ 2 file2và cột 1 của mỗi dòng được xác định bằng biểu thức chính quy:

^(\S+).*

Ở trên nói từ đầu dòng, khớp mọi thứ không phải là khoảng trắng và lưu nó vào biến tạm thời $1. Nó được cứu bằng cách bọc parens xung quanh nó. Các .*nói để phù hợp với tất cả mọi thứ khác trên dòng.

Bit tiếp theo của dòng mà nói nhìn lên cột 1 chút mà chúng ta vừa lưu ở $1trong %namesbăm:

$names{$1}

Nếu nó có mặt ở đó, thì chúng tôi không muốn in nó. Nếu nó không ở đó, sau đó in nó.


2

Phương pháp 1 # Bash

#!/usr/bin/env bash
file1=$1
file2=$2

[[ $# -ne 2 ]]  && { echo -e "\n\tUsage: \t$0 file1 file2\n"; exit 1; }

while read line
do

        if ! grep -q "${line%% .*}" $file1; then
                echo "${line}"
        fi

done < $file2

Phương pháp 2 # Chỉ Grep

grep -v "$(< file1)" file2

grep đang làm việc, nhưng không bảo đảm


1

Hãy lấy nó làm

Tệp số 1: file1.txt

Tệp số 2: file2.txt

Sau đó chạy theo thiết bị đầu cuối

fgrep -vf test1.txt test2.txt > output.txt

output.txt sẽ chứa kết quả mong muốn.

Giải trình:

fgrep : print lines matching a pattern (from manual page)
-v  : get only non-matching rows
-f : obtain PATTERN from FILE (from manual page)

Điều này chỉ hoạt động nếu toàn bộ các dòng giống hệt nhau, nhưng người hỏi rõ ràng chỉ yêu cầu so sánh trên cột đầu tiên.
Adaephon
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.