複数のtxtファイルをマージする

複数のtxtファイルをマージする

複数の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

関連情報