例を挙げて質問します。 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に保存します。
これには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 の例の1つに基づいています。
export LC_ALL=C
comm -13 <(sort f1) <(sort f2)
f2
のみの行を報告します。
export LC_ALL=C
join -v2 <(sort f1) <(sort f2)
最初のフィールドがf2
のどの行の最初のフィールドとしても見つからないf1
の行を報告します。
(ksh93
、zsh
、bash
などのプロセス置換をサポートするシェルが必要です)。
ちょうど楽しみのために、ここに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}
そこにある場合は、印刷しません。ない場合は、印刷します。
方法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: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)