数値列を含む2つのファイルから一致する行を印刷します。

数値列を含む2つのファイルから一致する行を印刷します。

私は次のことをしようとしました。

  • 3つの数字列を持つファイルがあり、1つの数字列を持つ小さなファイルと比較して一致する行を印刷したいと思いました。
  • 私は使用していますが、grep -F常に一致しない行を提供します。

答え1

私の考えでは、101より小さなファイルが含まれているときに一致する10ものと同じものが表示されます。これは、10が101の部分文字列であるためです。

デフォルトファイルにフィールドが1つしかない場合は、-x正確な一致のためにgrepオプションを使用できます。例えば

grep -x -F -f smallerfile.txt mainfile.txt

3つのフィールドがあるため、各フィールドを個別に一致させる必要があるため、perlやawkなどを使用する必要があります。たとえば、awkを使用すると、次のようになります。

$ cat smallerfile.txt 
1
10
25
152

$ cat mainfile.txt 
1 2 3
5 10 15
10 11 12
100 101 102
150 151 152
250 255 260

$ awk 'FNR == NR { nums[$1]++ ; next }
       $1 in nums || $2 in nums || $3 in nums' smallerfile.txt mainfile.txt
1 2 3
5 10 15
10 11 12
150 151 152

しかし、3つ以上のフィールドをチェックする必要がある場合は、スクリプトを作成または更新するのが面倒です。これを回避するには、各フィールド(数に関係なく)を繰り返し、そのうちの1つの値が配列にあることを確認するawk関数を作成しますnums。例えば

$ awk 'function check_all_fields() {
         for (i=1; i<=NF; i++) {
           if ($i in nums) return 1
         }
         return 0
       }
       FNR == NR { nums[$1]++ ; next }
       check_all_fields()' smallerfile.txt mainfile.txt
1 2 3
5 10 15
10 11 12
150 151 152

ご覧のとおり、出力は最初のバージョンと同じです。

check_all_fields()関数が入力行で一致するフィールドを確認すると、1(true)が返されます。現在の行に1がまったく表示されない場合は0(false)を返します。

答え2

近所を活用して検索文字列をsed案内する次のアプローチを使用してこれを行うことができます。grep

sed -e 's/.*/\\<&\\>/' f1 | grep -Ef - f3col

出力:-

1 2 3
5 10 15
10 11 12
150 151 152

awk図のように操作できます。まず、a[...]単一の列ファイルの列に基づく連想配列を形成します。次に、3列ファイルの各行でフラグを初期化pし、単一の列ファイルのフィールドに一致するデータがある場合、フラグをインクリメントします。その後、for ループの終了時にフラグが少なくとも 1 回増加した場合、条件付きでレコードを印刷します。

awk '
NR==FNR{a[$1];next}
{
  for (p=i=1; i<=NF; i++) if ($i in a) p++
}p>1
' f1 f3col

pythonデータ構造自体は、set以下のようにセットの交差集合が空でない場合を印刷する実装をサポートします。

python3 -c 'import sys
file1,file2 = sys.argv[1:]

with open(file1) as f1, open(file2) as f2:
  s1 = { _.rstrip() for _ in f1 }
  for _ in f2:
    s2 = set(_.rstrip().split())
    if bool(s2 & s1):
      print(_,end="")
' f1 f3col

構文を使用して、POSIX sedまず単一の列ファイルを使用してPOSIX sedコードを生成し、それを3列ファイルに適用します。

sed -e '
  h;G;G
  s/.*/^&$/
  s|\n| /b&/ |g
  s|.*|/&/b|;$a\
d
' f1 | sed -f - f3col

perlこれはいくつかの方法で行うことができます。

perl -lane '
  @A || chomp(@A=<STDIN>);
  for my $f (@F) {
    print,last if grep { $f == $_ } @A;
  }
' f3col < f1

perl -MList::Util=any -lane '
  chomp(@A=<STDIN>) if !@A;
  print if 
    any {
      my $f = $_;
      any { $_ == $f } @A;
    } @F;
' f3col < f1

関連情報