2014-06-20 21 views
11

Tôi có hai tệp không phân loại có một số điểm chung.Làm thế nào để loại bỏ các dòng chung giữa hai tập tin mà không cần phân loại?

file1.txt

Z 
B 
A 
H 
L 

file2.txt

S 
L 
W 
Q 
A 

Con đường tôi đang sử dụng để loại bỏ dòng chung như sau:

sort -u file1.txt > file1_sorted.txt 
sort -u file2.txt > file2_sorted.txt 

comm -23 file1_sorted.txt file2_sorted.txt > file_final.txt 

Output:

B 
H 
Z 

Vấn đề là tôi muốn giữ lại thứ tự của file1.txt, ý tôi là:

đầu ra mong muốn:

Z 
B 
H 

Một giải pháp tôi tought đang làm một vòng lặp để đọc tất cả các dòng của file2 .txt và:

sed -i '/^${line_file2}$/d' file1.txt 

Nhưng nếu các tập tin là lớn hiệu suất có thể hút.

  • Bạn có thích ý tưởng của tôi không?
  • Bạn có cách nào khác để làm điều đó không?

Trả lời

12

grep hoặc awk:

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

'a [$ 0] = 7' Tại sao bằng bảy? Cảm ơn! :) – harrison4

+2

@JohnDoe, chúng tôi chỉ cần số không khác, 7 và 1 không có sự khác biệt. Tôi thay đổi nó thành 1, nếu nó làm cho bạn cảm thấy thoải mái. :-) – Kent

+0

Vâng, tôi cảm thấy tốt hơn bây giờ. :) – harrison4

10

Bạn chỉ có thể sử dụng grep (-v để đảo ngược, -f cho tệp). dòng grep từ input1 không phù hợp với bất kỳ dòng trong input2:

grep -vf input2 input1 

Cung cấp:

Z 
B 
H 
+4

sẽ tốt hơn nếu có tùy chọn '-F -w hoặc -x'? ví dụ. trường hợp chuỗi con. – Kent

3

Tôi đã viết một kịch bản ít Perl mà tôi sử dụng cho loại điều này. Nó có thể làm nhiều hơn những gì bạn yêu cầu nhưng nó cũng có thể làm những gì bạn cần:

#!/usr/bin/env perl -w 
use strict; 
use Getopt::Std; 
my %opts; 
getopts('hvfcmdk:', \%opts); 
my $missing=$opts{m}||undef; 
my $column=$opts{k}||undef; 
my $common=$opts{c}||undef; 
my $verbose=$opts{v}||undef; 
my $fast=$opts{f}||undef; 
my $dupes=$opts{d}||undef; 
$missing=1 unless $common || $dupes;; 
&usage() unless $ARGV[1]; 
&usage() if $opts{h}; 
my (%found,%k,%fields); 
if ($column) { 
    die("The -k option only works in fast (-f) mode\n") unless $fast; 
    $column--; ## So I don't need to count from 0 
} 

open(my $F1,"$ARGV[0]")||die("Cannot open $ARGV[0]: $!\n"); 
while(<$F1>){ 
    chomp; 
    if ($fast){ 
    my @aa=split(/\s+/,$_); 
    $k{$aa[0]}++; 
     $found{$aa[0]}++; 
    } 
    else { 
    $k{$_}++; 
     $found{$_}++; 
    } 
} 
close($F1); 
my $n=0; 
open(F2,"$ARGV[1]")||die("Cannot open $ARGV[1]: $!\n"); 
my $size=0; 
if($verbose){ 
    while(<F2>){ 
     $size++; 
    } 
} 
close(F2); 
open(F2,"$ARGV[1]")||die("Cannot open $ARGV[1]: $!\n"); 

while(<F2>){ 
    next if /^\s+$/; 
    $n++; 
    chomp; 
    print STDERR "." if $verbose && $n % 10==0; 
    print STDERR "[$n of $size lines]\n" if $verbose && $n % 800==0; 
    if($fast){ 
     my @aa=split(/\s+/,$_); 
     $k{$aa[0]}++ if defined($k{$aa[0]}); 
     $fields{$aa[0]}=\@aa if $column; 
    } 
    else{ 
     my @keys=keys(%k); 
     foreach my $key(keys(%found)){ 
      if (/\Q$key/){ 
      $k{$key}++ ; 
      $found{$key}=undef unless $dupes; 
      } 
     } 
    } 
} 
close(F2); 
print STDERR "[$n of $size lines]\n" if $verbose; 

if ($column) { 
    $missing && do map{my @[email protected]{$fields{$_}}; print "$aa[$column]\n" unless $k{$_}>1}keys(%k); 
    $common && do map{my @[email protected]{$fields{$_}}; print "$aa[$column]\n" if $k{$_}>1}keys(%k); 
    $dupes && do map{my @[email protected]{$fields{$_}}; print "$aa[$column]\n" if $k{$_}>2}keys(%k); 
} 
else { 
    $missing && do map{print "$_\n" unless $k{$_}>1}keys(%k); 
    $common && do map{print "$_\n" if $k{$_}>1}keys(%k); 
    $dupes && do map{print "$_\n" if $k{$_}>2}keys(%k); 
} 
sub usage{ 
    print STDERR <<EndOfHelp; 

    USAGE: compare_lists.pl FILE1 FILE2 

     This script will compare FILE1 and FILE2, searching for the 
     contents of FILE1 in FILE2 (and NOT vice versa). FILE one must 
     be one search pattern per line, the search pattern need only be 
     contained within one of the lines of FILE2. 

    OPTIONS: 
     -c : Print patterns COMMON to both files 
     -f : Search only the first characters of each line of FILE2 
     for the search pattern given in FILE1 
     -d : Print duplicate entries  
     -m : Print patterns MISSING in FILE2 (default) 
     -h : Print this help and exit 
EndOfHelp 
     exit(0); 
} 

Trong trường hợp của bạn, bạn sẽ chạy nó như

list_compare.pl -cf file1.txt file2.txt 

Tùy chọn -f làm cho nó chỉ so sánh từ đầu tiên (được xác định bởi khoảng trống) của tệp2 và tăng tốc rất nhiều thứ. Để so sánh toàn bộ dòng, hãy xóa -f.

Các vấn đề liên quan