シェルスクリプトで2番目のファイルを最初の列と比較し、2番目のファイルから重複行を削除する


9

例を挙げて質問します。2つのファイルがあります。

ファイル#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

ファイル#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

望ましい出力

ファイル#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

最初の列を使用してファイル1とファイル2を比較し、ファイル1で一致する行全体または行をファイル2から削除します。また、結果を3番目のファイル#3に保存します。

回答:


10

awkこれに使用できます:

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

説明:

  • FNR == NR:このテストは、レコード数がファイル内のレコード数と等しい場合に当てはまります。これは最初のファイルにのみ当てはまります。2番目のファイルNRはfile1 +の行数と同じになるためFNRです。

  • a[$1]:file1の最初のフィールドの配列要素インデックスを作成します。

  • next:次のレコードにスキップして、file1でこれ以上の処理が行われないようにします。

  • !($1 in a):最初のフィールド($ 1)が配列、つまりfile1に存在するかどうかを確認し、行全体を(file3に)出力します。

#awk wikiの例に基づいています


完璧な答え!!!
mtk 2013年

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

だけにある行を報告しf2ます。

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

f2最初のフィールドが見つからない行を、のどの行の最初のフィールドとしても報告しf1ます。

(次のようなプロセスの交代のサポート付きシェルを必要とするksh93zshまたはbash)。


2

ちょうど楽しみのために、ここに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};
}

$ ./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

細部

上記のPerlソリューションは2つのループで構成されています。最初のループはからすべての行を読み取りfile1、ハッシュを作成します。%namesここで、特定した各列が追加されます。

$names{11AA} = 1;

次に、2番目のwhileループが2番目のファイルで実行され、file2各行の列1が正規表現を使用して識別されます。

^(\S+).*

上記は行の最初から言って、スペースではないすべてのものに一致し、それを一時変数に保存します$1。かっこで囲んで保存します。.*ライン上の他のすべてと一致するように言います。

その行の次のビットは$1%namesハッシュに保存した1ビットの列を検索することを示しています。

$names{$1}

そこにある場合は、印刷したくありません。ない場合は、印刷します。


2

方法1#バッシュ

#!/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

方法2#Grepのみ

grep -v "$(< file1)" file2

grepは機能していますが、保証はされていません


1

それを得ることができます

ファイル#1:file1.txt

ファイル#2:file2.txt

次に、ターミナルで以下を実行します

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

output.txtには目的の結果が含まれます。

説明:

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

これは行全体が同一である場合にのみ機能しますが、質問者は最初の列でのみ比較を明示的に要求しました。
Adaephon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.