ファイルが複数あり、各ファイルの最初の列に基づいてマージする必要があります。
ファイル1:
foo 12
jhdfeg 25
kjfdgkl 37
ファイル2:
foo 23
jhdfeg 45
ファイル3:
foo 35
djhf 37
出力は次のようにする必要があります
file1 file2 file3
foo 12 23 35
jhdfeg 25 45 0
kjfdgkl 37 0 0
djhf 0 0 37
答え1
アッ方法:
joiner.awk
スクリプト:
#!/bin/awk -f
BEGIN {
f1=ARGV[1]; f2=ARGV[2]; f3=ARGV[3] # the 1st, 2nd and 3rd file names respectively
printf("%10s\t%s\t%s\t%s\n", "", f1, f2, f3) # printing header
}
{ a[$1][FILENAME]=$2 } # accumulating values
END {
for (i in a) {
printf("%-10s\t%d\t%d\t%d\n", i, a[i][f1], a[i][f2], a[i][f3])
}
}
使用法:
awk -f joiner.awk file1 file2 file3
出力:
file1 fil2 file3
kjfdgkl 37 0 0
foo 12 23 35
djhf 0 0 37
jhdfeg 25 45 0
答え2
perl -F'\s+' -lane '
$. == 1 and @ARGC = ($ARGV, @ARGV); # initialize the @ARGC array
exists $h{$F[0]} or $h[keys %h] = $F[0]; # needed to remember order
$h{$F[0]}->[@ARGC-@ARGV-1] = $F[1]; # populate hash
END {
$, = "\t"; # set the OFS to TAB
print q//, @ARGC; # print the first line with filenames
for my $key (@h) { # print remaninig lines with data
print $key,
map { $h{$key}->[$_] // 0 } 0 .. $#ARGC;
}
}
' file1 file2 file3 # ... you can give as many files here
出力
file1 file2 file3
foo 12 23 35
jhdfeg 25 45 0
kjfdgkl 37 0 0
djhf 0 0 37
答え3
あなたの例のように3つのファイルがある場合は、
join
魔法を使ってこれを行うことができます。まず、タブ区切りのファイル名を出力ファイルに書き込みます。
for i in File*; do printf "\t%s" "$i" >> RES; done
実際の結果に空白行を追加します。
printf '\n' >> RES
join
onを使用しFile1
てFile2
出力を一時ファイルにリダイレクトします。
join -a1 -a2 -e0 <(sort File1) -o 0 1.2 2.2 <(sort File2) > TEMP_FILE
ここで上記のコマンドの出力を再度使用してくださいFile3
(ここではパイプ()を使用することもできます|
)。
join -a1 -a2 -e0 <(sort TEMP_FILE) -o 0 1.2 1.3 2.2 <(sort File3) >> RES
スペースをタブに置き換えますRES
。
tr ' ' '\t' < RES > FINAL_RES
結果は次の場所にありますFINAL_RES
。
$ cat FINAL_RES
File1 File2 File3
foo 12 23 35
jhdfeg 25 45 0
kjfdgkl 37 0 0
答え4
ファイル数に関係なく、より一般的なアプローチは次のとおりですsed
。
sed '1{x;s/$/_/;x;}
/foo/{x;s/_/ 0_/g;x;}
G;s/^\([a-z]*\) *\([0-9]*\).*\n\(.*_\)\1\([^_]*\)0/\3\1\4\2/
s/^\([a-z]*\) *\([0-9]*\).*\n\([^_]*\)0_\(.*\)/\30_\4\1\3\2_/
$! {h;d;}
s/[^_]*_//
y/_/\n/' file*
これはfoo
、例に示すように、その行で始まるすべてのファイルに依存します。
sed
これで、仕組み、パターン空間、スペースの維持に関する基本がわかったので、説明は次のとおりです。
主なアイデアは、予約されたスペースに完全な出力テーブルを構築することです。各行に予約されているスペースには、そのポイントのテーブルと新しい行に必要なテンプレート行が含まれます。_
処理中に行区切り文字として使用します。今段階的に:
1{x;s/$/_/;x;}
これにより、_
テンプレート行の先頭に単一を使用して予約済みスペースが初期化されます。
/foo/{x;s/_/ 0_/g;x;}
/foo/
foo
新しいファイルの開始を示すインクルード行を指定します。この場合、次のコマンドが実行されます{}
。予約済みスペースのすべての行(実際のテーブル行とテンプレート行)が0
追加されます。後でその行のキーワードを検出すると、0
正しい数字に置き換えられます。キーワードが表示されない場合は保持0
されます。
G;s/^\([a-z]*\) *\([0-9]*\).*\n\(.*_\)\1\([^_]*\)0/\3\1\4\2/
「G」は、予約済みスペースをパターンスペースに追加します。コマンドs
は4つの部分で構成されています。最初の部分にはキーワードが含まれ、2番目の部分には値が含まれ、3番目の部分にはキーワードが2番目に表示されるまで(逆参照)、\(\)
改行文字の後のすべての項目が含まれます(したがって、これは予約済みスペースに追加されます)されたテーブルです)。\1
。 4番目の項目は、最後の項目を除く行のすべての項目を所有します0
。したがって、そのキーワードを含む既存の行を見つけ、0
すべてを改行文字に入れ、更新されたテーブルを保持します。
s/^\([a-z]*\) *\([0-9]*\).*\n\([^_]*\)0_\(.*\)/\30_\4\1\3\2_/
別の一致には newline が含まれているため、\n
テーブルでキーワードが見つからなかったことがわかります(そうでなければ、前の行から改行が削除された可能性があります。したがって、今回はキーワードで構成された新しい行を最後に追加します。テンプレート行の秘密です。0
新しいファイルごとに列を追加するため、列を削除すると、0
各ファイルにキーワードのない列が1つずつあります。0
$! {h;d;}
最後の行でない場合は、変更されたテーブルを再予約済みスペース(h
)に移動して再起動します(d
)。
s/[^_]*_//
最後の行の場合、テンプレート行は削除されます。
y/_/\n/
_
これは改行文字を置き換えます。また、必要に応じてスペースをタブに置き換えることもできます。
編集する
すべてのファイルがその行で始まるという仮定が間違っている場合は、各ファイルの先頭に追加の行を追加してコンテンツ全体を次にストリーミングするなど、新しいファイルが開始されるタイミングを知るための別のfoo
方法が必要です。sed
sed
for file in file*; do
echo Start of $file
cat $file
done | sed '1{x;s/$/__/;x;}
/Start of/{G;s/_/ 0_/g;s/Start of \(.*\)\n\([^_]*\)_\([^_]*\) 0/\2_\3 \1/;x;d;}
G;l;s/^\([a-z]*\) *\([0-9]*\).*\n\(.*_\)\1\([^_]*\)0/\3\1\4\2/
l;s/^\([a-z]*\) *\([0-9]*\).*\n\([^_]*\)0_\(.*\)/\3 0_\4\1\3\2_/
$! {h;d;}
s/[^_]*_//
y/_/\n/'
このバージョンでは、すべてのファイル名を列ヘッダーとして使用して、テーブルのヘッダー行も生成します。