以下のように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 0
0
-o
2.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
最初の列を関連配列のキーとして読み取り、key
2番目の列を関連値として読み込みます。
読み込み時にFile1
(もはや等しくない)、最初のNR
列に対応するキーがある場合は、2番目の列を配列の値に設定し、FNR
そのようなキー値がない場合は配列の値に設定します。key
0
算術コンテキストで初期化されていない値がゼロであるという事実を悪用して、コードを少し短くすることができます。
$ 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=1
mainfile
1
- 設定されると、最初のルールは無視され、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}")