配列に重複したインデックス値があります。

配列に重複したインデックス値があります。

次の文書が与えられた場合:

ファイル1:

7997,1
7997,2
7997,3
5114,1
5114,2

ファイル2:

7997,52,
5114,12,
4221,52,

file2awkのデータと比較する値で最初の列をインデックスに、2番目の列を値として最初のファイルから配列を作成するにはどうすればよいですか?

このような:

cat file1 file2 | awk -F, '{if(NF==2){arr[$1]=$2}else{if(arr[$1]){print arr[$1]","$0}}}'

希望の出力は次のとおりです。

1,2,3,7997,52
1,2,5114,12

答え1

1つの方法は次のとおりです。

$ awk -F, -vOFS=, 'NR==FNR{a[$1]=a[$1]","$2; next} 
                   ($1 in a){print a[$1],$0}' file1 file2 | 
    sed 's/^,\(.*\),$/\1/'
1,2,3,7997,52
1,2,5114,12

説明する

  • -F, -vOFS=,:入力フィールド区切り記号(-F)と出力フィールド区切り文字(実行時-vOFSに印刷される各値の間に挿入される文字列print $1,$2)をコンマに設定します。

  • NR==FNR{a[$1]=a[$1]","$2; next}FNR行番号です現在のファイルNRは入力行番号です。読み込む 2 つのファイルが与えられると、awkこれらの変数は最初のファイルを読み取るときにのみ同じです。したがって、最初のブロックは、NR==FNR{}最初のファイルを読み取るときにのみ実行されます。

    このブロックのコードは、a最初のフィールドでインデックス付けされた配列を作成します。ブロックが実行されるたびに、配列のインデックスに格納されている項目にコンマと2番目のフィールドの値が追加されます$1next最初のファイルの2番目のブロックが実行されないように、スクリプトの実行を続行せずに次の入力行にジャンプします。

    最初の実行はa[$1]空であるため、配列の先頭に追加のコンマが追加されます。sed最後の項目として削除します。

  • ($1 in a){print a[$1],$0}:これは2番目のファイルにあります。行の最初のフィールドが配列のインデックスである場合は、現在のa行()の対応するインデックスに関連する値を印刷します。a$0

  • sed 's/^,\(.*\),$/\1/':行の最初のカンマ()と一致し、括弧を使用して^,最後のコンマ()\(.*\),$を除くすべての項目をキャプチャします。次に、コンテンツ全体をキャプチャされたパターン(\1)に置き換えます。その結果、各行の最初と最後のコンマのみが削除されます。これは、スクリプトが行の先頭に追加する追加のコンマawkも削除することですfile2。目的の出力にも表示されないからです。

答え2

これを達成するために、およびFNR変数を使用できます。NR

awk -F "," '{
  if(FNR==NR){
    if (a[$1] != ""){
      a[$1]=a[$1]","$2
      }
    else{
      a[$1]=$2
      }
    }
    else{
      if (a[$1]!= ""){
        print a[$1]","$1","$2
        }
      }
    }' file1 file2

答え3

から始まる地震Pの完璧な答えそしてロジックをもう少し強化してみてください。これはもともと彼の答えに対するコメントでしたが、長すぎました(そしてはいそれ自体が有効な答えです。)ここにあります:

awk 'BEGIN {
  FS = ","
  OFS = ","
}

FNR == NR {
  if ($1 in a) {
    a[$1] = a[$1] OFS $2
  } else {
    a[$1] = $2
  }
  next
}

$1 in a {
  print a[$1], $1, $2
}' file1 file2

一般的に言えば、そうしないでください特別な理由がない限り、代わりにif ($x in myarray)使用するのが最善です。if (myarray[$x] != "")配列の要素がまだ作成されていないことを確認するには、最初のバージョンを使用してください。知っていれば持つ作成され、空の文字列でないことを確認するには、2番目の文字列を使用してください。 2番目の方法の秘密は、配列要素に名前を付けるだけで、myarray[$x]その値を確認する状況でも自動的に生成されるということです。これにより、プリントアレイを使用すると、場合によっては問題が発生する可能性がありますfor (index in myarray)

そしてを使用する場合、print var1 "," var2 "," var3これはOFS正しいユースケース(出力フィールドの区切り文字)です。ブロックにOFSを設定すると、BEGINスクリプト全体の出力形式をすばやく簡単に変更できます。

最後に、最初のファイルで1つの操作を実行し、2番目またはその他のファイルで別の操作を実行するときにドアで終わるFNR == NRパターンブロックがif / elseブロックよりもきれいだと思います。next

関連情報