awk匹配,合并两个文件,同时修改列输入并向输出文件添加一个额外的列

时间:2016-08-26 20:32:33

标签: bash unix awk merge

我想合并2个文件并将其分配到新文件,同时在unix中使用优选的awk添加新的不存在的列:

文件1:VDR.txt没有标题,空格分隔,如下所示:

chr12-45000000-50000000 --- rs192072617 48225416 0.000 0.270 0.999 0 -1 -1 -1
chr12-45000000-50000000 --- rs181728325 48225429 0.000 0.144 1.000 0 -1 -1 -1
chr12-45000000-50000000 --- rs187216594 48225500 0.000 0.007 1.000 0 -1 -1 -1

文件2:METAL1.tbl有一个标题,标签分隔,如下所示:

MarkerName      Allele1 Allele2 Weight  Zscore  P-value Direction       HetISq  HetChiSq        HetDf   HetPVal
rs192072617       a       g       2887.00 1.579   0.1143  ++      0.0     0.032   1       0.8579
rs7929618       c       g       2887.00 -1.416  0.1568  -+      47.4    1.899   1       0.1681
rs181728325      t       c       2887.00 1.469   0.1419  ++      73.9    3.830   1       0.05033
rs7190157       a       c       2887.00 1.952   0.05088 +-      72.7    3.669   1       0.05542
rs12364336      a       g       2887.00 -1.503  0.1328  -+      69.8    3.306   1       0.06902
rs187216594       t       c       2887.00 -0.082  0.9349  +-      74.8    3.964   1       0.04649
rs12562373      a       g       2887.00 -0.290  0.7717  -+      0.0     0.150   1       0.6984

文件的行数不等,第一个文件(VDR.txt)比第二个文件(METAL1.tbl)短得多。

我想:

  1. 将这些文件合并到第一个文件(VDR.txt)的第3列和第二个文件的第1列(METAL1.tbl)。
  2. 仅保留第一个文件(VDR.txt)中的第1,2,3和4列以及第二个文件中的所有列(METAL1.tbl)。
  3. 仅保留第一个短划线"-"之前的字符从第一个文件的第一列(VDR.txt)
  4. 在输出文件中添加一个新列,重复某个字符串(例如“VDR”)
  5. 输出文件不必有标题,但是如果有必要的话,最好将它放在下面给出。
  6. 所以我希望在最后有一个输出文件(output.txt):

    gene    MarkerName  chr BP  impute  Allele1 Allele2 Weight  Zscore  P-value Direction   HetISq  HetChiSq    HetDf   HetPVal
    VDR rs192072617 chr12   48225416    --- a   g   2887    1.579   0.1143  ++  0   0.032   1   0.8579
    VDR rs181728325 chr12   48225429    --- t   c   2887    1.469   0.1419  ++  73.9    3.83    1   0.05033
    VDR rs187216594 chr12   48225500    --- t   c   2887    -0.082  0.9349  +-  74.8    3.964   1   0.04649
    

    我的尝试:

    $ awk 'FNR==NR {a[$1]=$1" "$2" "$3" "$4" "$5;next}{print $3, gensub(/-.*/, "", $1), $4, $2, a[$3]}' METAL1.tbl VDR.txt
    

    它确实以正确的方式获取chr列和列顺序,但不幸的是只打印了VDR.txt中的所需列而不是合并文件。

    我知道这是一个相当复杂的例子,任何帮助或建议都会非常感激。

    谢谢,
    梅尔

3 个答案:

答案 0 :(得分:3)

只要不需要标题行,就可以直接使用一个相当简单的awk脚本:

$ awk 'FNR == NR { sub(/-.*/, "", $1); row[$3] = "VDR " $3 " " $1 " " $4 " " $2 }
>      FNR != NR { if ($1 in row) { name = $1; $1 = ""; print row[name] $0 } }' \
>      VDR.txt METAL1.tbl
VDR rs192072617 chr12 48225416 --- a g 2887.00 1.579 0.1143 ++ 0.0 0.032 1 0.8579
VDR rs181728325 chr12 48225429 --- t c 2887.00 1.469 0.1419 ++ 73.9 3.830 1 0.05033
VDR rs187216594 chr12 48225500 --- t c 2887.00 -0.082 0.9349 +- 74.8 3.964 1 0.04649
$

必须按照显示的顺序列出文件才能使用。

FNR == NR行处理第一个文件。 sub在第一个字段中删除了第一个短划线及其后面的所有内容;赋值由$3中的标记名键控,并包含行开头的信息 - 固定代码,标记名称,缩小的染色体编号,BP和标记为'的破折号组。 &插补39#;

FNR != NR行处理其他文件。当第1列中的值与row数组中的键匹配时,则从当前行中删除键(在$0的开头留下原位),然后打印row$0联系在一起。

没有必要特别对待标题线;值MarkerName不匹配第一个文件中的任何实际标记名称,因此该行只是被忽略。

答案 1 :(得分:2)

$ cat > test.awk
NR==FNR {
    sub(/-.*/,"",$1)                                      # remove from 1st dash forward
    a[$3]="VDR" OFS $3 OFS $1 OFS $4 OFS $2               # cols 1-4 of the 1st file
    next                                        
} 
FNR==1 {
    printf "%s", "H0" OFS "H3" OFS "H1" OFS "H4" OFS "H2" # 1st part of header
} 
FNR==1 || $1 in a {                                       # header and matching rows
    print a[$1], $0                                       # print'em
}
$ awk -f test.awk VDR.txt METAL1.tbl
H0      H3      H1      H4      H2      MarkerName      Allele1 Allele2 Weight Zscore   P-value Direction       HetISq  HetChiSq        HetDf   HetPVal
VDR     rs192072617     chr12   48225416        ---     rs192072617     a      g2887.00 1.579   0.1143  ++      0.0     0.032   1       0.8579
VDR     rs181728325     chr12   48225429        ---     rs181728325     t      c2887.00 1.469   0.1419  ++      73.9    3.830   1       0.05033
VDR     rs187216594     chr12   48225500        ---     rs187216594     t      c2887.00 -0.082  0.9349  +-      74.8    3.964   1       0.04649

作为一个单行:

awk 'NR==FNR { sub(/-.*/,"",$1); a[$3]="VDR" OFS $3 OFS $1 OFS $4 OFS $2; next} FNR==1 {printf "%s", "H0" OFS "H3" OFS "H1" OFS "H4" OFS "H2"} FNR==1 || $1 in a {print a[$1], $0}' VDR.txt METAL1.tbl

答案 2 :(得分:1)

我已经对两个数据文件进行了排序以使用join命令 - 这会影响输出中的行顺序 - 如果不希望我可以使用其他方法

export LANG=C
genef=$1
metalf=$2
gene=$(basename $genef .txt)
join -13 -21 <(sort -k3,3 $genef) <(sort -k1,1 $metalf)|
awk -vgene=$gene '
{
  marker=$1
  chr=substr($2, 1, index($2, "-")-1)
  bp=$4
  impute=$3
  printf("%s\t%s\t%s\t%s\t%s", gene, marker, chr, bp, impute)
  for(i=12; i<=NF; ++i)
    printf("\t%s", $i)
  printf("\n")
}
'

这是制表符分隔的输出

VDR     rs181728325     chr12   48225429        ---     t       c       2887.00 1.469    0.1419  ++      73.9    3.830   1       0.05033
VDR     rs187216594     chr12   48225500        ---     t       c       2887.00 -0.082   0.9349  +-      74.8    3.964   1       0.04649
VDR     rs192072617     chr12   48225416        ---     a       g       2887.00 1.579    0.1143  ++      0.0     0.032   1       0.8579