複数のtxtファイルがあり、そのうち3つは次のとおりです。
ファイル1:
sample input filtered
5809378 1 2
5811151 3 4
5811237 5 6
ファイル2:
sample chi tri
5809378 7 8
5811151
5811237 9 10
ファイル3:
sample bra doe
5809378 11
5811151 12
5811237 13 14
この3つのファイルを最初の列(サンプルID)に基づいて1つのファイルにマージしようとしているので、出力は次のようになります。
sample input filters chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14
そのデータがない場合はゼロが必要で、最悪の場合は空のタブが必要です。
awkとJoinを試しましたが、最良の解決策が見つかりませんでした。誰でもどんなアイデアがありますか?
答え1
私の観点から見ると、file3は次の行のため完全に正確ではありません。
5811151 12
ファイルの読み方によっては、2番目または3番目の列に数字「12」がある場合があります(列区切り文字は定義されておらず、どこでも異なります)。
それでも。
a=$(cat file1|awk '{if($2==""){$2="0"};if($3==""){$3="0"}; print $1,$2,$3}'|sort);
for f in file2 file3; do
b=$(cat $f|awk '{if($2==""){$2="0"};if($3==""){$3="0"}; print $1,$2,$3}'|sort);
a=$(join -j 1 <(echo "${a}") <(echo "${b}"));
done;
echo "${a}"|sort -n
出力は次のとおりです
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 12 0
5811237 5 6 9 10 13 14
だから私たちは
1)キャプチャされたすべてのファイルが変換されます。
cat file|awk '{if($2==""){$2="0"};if($3==""){$3="0"}; print $1,$2,$3}'|sort
欠落している数字を「0」に置き換えて行を並べ替えます。
2) ループから次のファイルをインポートし、前の結果にマージします。
join -j 1 file_current file_next
したがって、「for f in file2 file3; do」行は、「for f in file2 file3 file4 file5 file6; do」など、より多くのファイルを含むように変更できます。
3)結果を印刷し、文字列の値に基づいてソートします。(最初に列名をソートして印刷します。)必要に応じて、ここで出力形式を指定することもできます。
答え2
ファイルにタブ区切りの列があり(3行目でどの列が空であるかがわかりますfile3
)、例のように最初の列を並べ替えると仮定すると、bashスクリプトは次のようになります。
#!/bin/bash
function fixup() { # Add 0's to blank columns
awk -v cols="$2" 'BEGIN { FS = OFS = "\t" }
{ for (i = 1; i <= cols; i++)
if ($i == "") $i = 0
} 1' "$1"
}
join --header -t$'\t' -j1 \
<(join --header -t$'\t' -j1 <(fixup "$1" 3) \
<(fixup "$2" 3)) \
<(fixup "$3" 3)
すること:
$ ./combine file1 file2 file3
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14
(実際にはGNU coreutilsバージョンが必要ですjoin
)。
答え3
スタートアップファイルがタブで区切られ、空のフィールドがまだタブで区切られていると仮定すると、awkを使用して不足している列にゼロを埋めることができます。たとえば、次のようになります。
awk -F' ' '!$2{$2=0}!$3{$3=0}{print}' file1 > file1-n
awk -F' ' '!$2{$2=0}!$3{$3=0}{print}' file2 > file3-n
awk -F' ' '!$2{$2=0}!$3{$3=0}{print}' file3 > file3-n
確かにawk -F '<TAB>'
。その後、貼り付けを使用してマージし、別のawkを使用して不要な列をフィルタリングできます。
bash-$ paste file1-n file2-n file3-n | awk {'print $1, $2, $3, $5, $6, $8, $9'}
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14
または人の読みやすさが重要な場合は、列を区別してください。
bash-$ paste file1-n file2-n file3-n | awk {'printf "%-7s %-5s %-8s %-3s %-3s %-3s %-3s\n", $1, $2, $3, $5, $6, $8, $9'}
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14
答え4
tab
区切り文字があると仮定する別のオプション
0
まず、ダブルスの間やテキスト(タイトルなど)や数字のない行の末尾にを挿入してtab
ファイルを修正します。$
[^[:alnum:]]
TAB=$'\t'; sed -Ei "s/([^[:alnum:]]|${TAB})($|${TAB})/\10\2/g" file*
じゃあjoin
その人だよ
join --header file2 file3 | join --header file1 - | column -t
出力
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14