file1 と file2 の間の部分一致に基づいて列を照合し、一致しない行を印刷します。

file1 と file2 の間の部分一致に基づいて列を照合し、一致しない行を印刷します。

file1

HIB12  
VH6|KB4  
KB4  
KB4|LKM98|HIB12  

file2

c1 c1 c3 c4 HIB12|LKM98 c6  
c1 c1 c3 c4 KB4|LKM98 c6  
c1 c1 c3 c4 LL15|VH6  
c1 c1 c3 c4 ZZ16|YY15 c6 
c1 c1 c3 c4 ZZ16 c6 
c1 c1 c3 c4 AB1 c6  

どちらのファイルもタブで区切られます。ファイル1の列1は、ファイル2の列5と部分的に一致します。両方の列の値は「|」で区切られます。 file1の列1の値がファイル5の列5の値と一致する場合、その行は出力に印刷されず、出力に一致しない他の行がなければなりません。 。試しましたが、期待した結果が得られませんでした。

awk 'BEGIN{FS=OFS="\t"} NR==FNR {a[$1]=$5; next} {for (i in a) if (index(i, $5)) print $0, a[i]}' file2 file1

expected output

c1 c1 c3 c4 ZZ16|YY15 c6 
c1 c1 c3 c4 ZZ16 c6  

答え1

GNU awkを使用したマルチキャラRS:

$ awk '
    NR==FNR { a[$0]; next }
    { split($5,v,"|"); for (i in v) if (v[i] in a) next; print }
' FS='\t' RS='[[:space:]|]+' file1 RS='\n' file2
c1 c1 c3 c4 ZZ16|YY15 c6
c1 c1 c3 c4 ZZ16 c6
c1 c1 c3 c4 AB1 c6

または awk を使用してください。

$ awk '
    NR==FNR { for (i=1; i<=NF; i++) a[$i]; next }
    { split($5,v,"|"); for (i in v) if (v[i] in a) next; print }
' FS='|' file1 FS='\t' file2
c1 c1 c3 c4 ZZ16|YY15 c6
c1 c1 c3 c4 ZZ16 c6
c1 c1 c3 c4 AB1 c6

答え2

すべてのawkと互換性があります。

awk 'BEGIN{FS=OFS="\t"}NR==FNR{split($0,vals,"|");for(i in vals){v[vals[i]]}}NR!=FNR{hide=0;for(j in v){if($5~j){hide=1}};if(!hide){print}}' ./file1 ./file2

私の結果は次のとおりです

c1 c1 c3 c4 ZZ16|YY15 c6
c1 c1 c3 c4 ZZ16 c6
c1 c1 c3 c4 AB1 c6

説明する:

NR==FNR:最初のファイルでは同じですNRFNR

{v[vals[i]]}:値を受け入れない連想配列を作成します。

if($5~j){hide=1}:5番目のフィールドに許可されていない値がある場合は、非表示の行を設定します。

hide=0:新しい行の非表示状態をリセットします。

答え3

$ perl -lane '
    # is this the first file? ($fc is file counter)
    if ($fc == 0) {
      # split first field on pipe chars                         
      my @p = split /\|/, $F[0];
      # use as keys for %patterns hash
      foreach my $p (@p) { $patterns{$p} = 1 };
    } else {
     print unless $F[4] =~ /$regex/;
    };

    if (eof) { # end of file
      if ($fc == 0) { # is this still the first (zeroth) file?
        # use keys of %patterns to build a regular expression
        $regex = join "|", keys %patterns;
      };
      $fc++;
    }' file1 file2
c1      c1      c3      c4      ZZ16|YY15       c6
c1      c1      c3      c4      ZZ16    c6
c1      c1      c3      c4      AB1     c6

ところで、ここには中間変数が少なく、コメントがないより短いバージョンがあります。

perl -lane '
  if ($fc == 0) {
    foreach (split /\|/, $F[0]) { $patterns{$_} = 1 };
  } else {
   print unless $F[4] =~ /$regex/;
  };

  if (eof) {
    $regex = join "|", keys %patterns if ($fc == 0);
    $fc++;
  }' file1 file2

読めないようにしたい場合は、変数名を減らしてテストを短くしますが、同等の($c==0)テストに変更し(初心者にとっては理解しにくいのでボーナスです!)、すべてを1行に(!$c)圧縮し、余分なスペースを削除して半文字 - コロンいいえ操作方法を変更してください。一部の人々はこれを好む - マゾヒズム貨物崇拝FTW!

perl -lane 'if(!$c){foreach(split/\|/,$F[0]){$p{$_}=1}}else{print unless $F[4]=~/$regex/};if(eof){$regex=join"|",keys %p if(!$c);$c++}' file1 file2

答え4

2番目のファイルでは、5番目のフィールドにはすでに論理要素ORが含まれています。

awk '
NR==FNR {A[$1]; next}
        {for(i in A)
                if(i ~ "^("$5")$") next
        print}
' RS='[\n|]' file1 RS='\n' file2

これで、条件付き行の始まりと終わり、および括弧のアンカーポイントのみを置き換えることができます。

関連情報