2つのファイルを列ごとにマージし、エントリが欠落している場合は0を追加します。

2つのファイルを列ごとにマージし、エントリが欠落している場合は0を追加します。

以下のように2つのファイルがあります。 File 2に見つからない項目がある場所に0を追加して、File 1とFile 2の2番目の列にあるすべての項目を含むマスターファイルを作成する方法を見つけようとしています。これらのファイルはすべてタブで区切られます。コマンドを試しましたが、機能しjoinませんでした。

  • の例File1
    orange
    banana
    berry
    cherry
    strawberry
    
  • File2:
    orange   1   
    banana   2   
    cherry   1   
    
  • 希望の出力
    Output    Value
    orange     1
    banana     2
    berry      0
    cherry     1
    strawberry 0
    

私が試したこと:

join File1 File2 |less

答え1

$ join -a 1 -e 0 -o 0,2.2 <(sort File1) <(sort File2)
banana 2
berry 0
cherry 1
orange 1
strawberry 0

joinファイル間のリレーショナルJOIN操作を実行するために使用されます。これを行うには、両方のファイルを並べ替える必要があり、これが各プロセスの交換時にファイルを並べ替える理由です(必要に応じてデータを事前に並べ替えることができます)。このコマンドは、最初の入力ファイル()のすべての行を一覧表示し、不足している-a 1フィールドを()に置き換えます。出力のフィールドは、関連付けられたフィールド(デフォルトでは各ファイルの最初のフィールドであり、オプションの引数に書き込まれます)と2番目のファイルの2番目のフィールド()です。0-e 00-o2.2

利点:高速(特にデータがすでにソートされている場合)、メモリ効率が良いです。
欠点:データを並べ替えます。


元の順序を維持するには、次のものをFile1使用できますawk

$ awk 'NR == FNR { key[$1] = $2; next } { $2 = ($1 in key) ? key[$1] : 0 }; 1' File2 File1
orange 1
banana 2
berry 0
cherry 1
strawberry 0

File2最初の列を関連配列のキーとして読み取り、key2番目の列を関連値として読み込みます。

読み込み時にFile1(もはや等しくない)、最初のNR列に対応するキーがある場合は、2番目の列を配列の値に設定し、FNRそのようなキー値がない場合は配列の値に設定します。key0

算術コンテキストで初期化されていない値がゼロであるという事実を悪用して、コードを少し短くすることができます。

$ awk 'NR == FNR { key[$1] = $2; next } { $2 = 0+key[$1] }; 1' File2 File1
orange 1
banana 2
berry 0
cherry 1
strawberry 0

利点:出力がソートされますFile1
欠点:データはFile2メモリに保存されます(多くの行を読み取る場合にのみ重要です)。

答え2

これを行うコマンドはわかりませんが、次のようにスクリプトで作成できます。

while IFS='' read -r l1; do
  grep "^${l1}" File2 || echo -e "${l1}\t0"
done < <(cat File1)

答え3

使用できますが、awkバッファリングが必要ですFile2巨大通常、その可能性は低いですが、ファイルが制限に達する可能性があります。

awk 'BEGIN{FS=OFS="\t"}
     !mainfile{val[$1]=$2;next}
     {if ($1 in val) {$2=val[$1]} else {$2=0}} 1' File2 mainfile=1 File1

仕組みは次のとおりです。

  • 処理する前に、入力フィールドと出力フィールドの区切り文字をTABに設定します。
  • 初期化されていない変数で示された最初の入力ファイル(File2この場合)を処理するときは、mainfile各「フルーツ」の「値」を関連配列に書き込むだけですval。その後すぐに次の入力行に処理をスキップします(そして処理時にのみ適用する必要がある部分はスキップしますFile1)。
  • に設定するawkステートメントは。mainfile=1mainfile1
  • 設定されると、最初のルールは無視され、2番目のルールのみmainfileが処理されます。ここでは、列1の項目にマップされた「値」があることを確認します。その場合は、その値を列2に使用し、そうでない場合は列2をに設定します0
  • 1ルールブロックの外側にあるように見えるものは、awk修正を含む現在の行を印刷するように指示します。

答え4

Pythonで素早く実装できるようです。

#!/usr/bin/env python3
"""
Overly grande solution to the problem posed in the question.
"""
import sys

# Check whether the user specified two arguments to the script
if not len(sys.argv) == 3:
  sys.stderr.write(f"Usage: {sys.argv[0]} File1 File2")
  sys.exit(-1)

# Empty dictionary
dictionary = {}

# Fill the dictionary with zero-entries from the first file
with open(sys.argv[1]) as file:
  for line in file:
   dictionary[line.strip()] = 0

# Replace the zero entries when found in second file
with open(sys.argv[2]) as file:
  for line in file:
    entry, value = line.split()
    dictionary[entry] = int(value)

# print the result table
print("Output\tValue")
for key, value in dictionary.items():
  # We're using the format string syntax to give the count
  # field a constant length of 8, so that things are nicely
  # right-aligned.
  print(f"{key}\t{value:8}")

関連情報