用awk替换列,保留格式

时间:2014-03-05 16:11:35

标签: replace awk format

我有一个 a.pdb 文件,

ATOM      1  N   ARG     1       0.000   0.000   0.000  1.00  0.00           N
ATOM      2  H1  ARG     1       0.000   0.000   0.000  1.00  0.00           H
ATOM      3  H2  ARG     1       0.000   0.000   0.000  1.00  0.00           H
ATOM      4  H3  ARG     1       0.000   0.000   0.000  1.00  0.00           H

a.xyz 文件为

16.388 -5.760 -23.332
17.226 -5.608 -23.768
15.760 -5.238 -23.831
17.921 -5.926 -26.697

我想用a.xyz替换a.pdb的第6和第8列。更换后,我需要维护a.pdb的标签/空格/列。

我试过了

awk 'NR==FNR {fld1[NR]=$1; fld2[NR]=$2; fld3[NR]=$3; next} {$6=fld1[FNR]; $7=fld2[FNR]; $8=fld3[FNR]}1' a.xyz a.pdb 

但它没有保留格式。

3 个答案:

答案 0 :(得分:9)

这正是GNU awk中split()的第4个arg的发明,是为了促进:

gawk '
NR==FNR { pdb[NR]=$0; next }
{
    split(pdb[FNR],flds,FS,seps)
    flds[6]=$1
    flds[7]=$2
    flds[8]=$3
    for (i=1;i in flds;i++)
        printf "%s%s", flds[i], seps[i]
    print ""
}
' a.pdb a.xyz

ATOM      1  N   ARG     1       16.388   -5.760   -23.332  1.00  0.00           N
ATOM      2  H1  ARG     1       17.226   -5.608   -23.768  1.00  0.00           H
ATOM      3  H2  ARG     1       15.760   -5.238   -23.831  1.00  0.00           H
ATOM      4  H3  ARG     1       17.921   -5.926   -26.697  1.00  0.00           H

答案 1 :(得分:3)

不是一般解决方案,但这可能适用于这种特殊情况:

awk 'NR==FNR{for(i=6; i<=8; i++) A[FNR,i]=$(i-5); next} {for(i=6; i<=8; i++) sub($i,A[FNR,i])}1' file2 file1

awk '{for(i=6; i<=8; i++) if(NR==FNR) A[FNR,i]=$(i-5); else sub($i,A[FNR,i])} NR>FNR' file2 file1
但是,有一点转变。我们需要知道字段宽度以防止这种情况。

- 或者也许有子串:

awk 'NR==FNR{A[FNR]=$0; next} {print substr($0,1,p) FS A[FNR] substr($0,p+length(A[FNR]))}' p=33 file2 file1

- 在OP的原始解决方案中更改它:

awk 'NR==FNR {fld1[NR]=$1; fld2[NR]=$2; fld3[NR]=$3; next} {sub($6,fld1[FNR]); sub($7,fld2[FNR]); sub($8,fld3[FNR])}1' file file1

与前两个建议具有相同的限制。

所以1,2和4使用sub替换,这不是防水解决方案,因为早期的字段可能会干扰并且它使用正则表达式而不是字符串(因此正则表达式点碰巧与实际匹配dot),但是通过这个特殊的输入,它可能会泛起来......

可能是nr。 3将是一种更加万无一失的方法..

- edit-- 我认为这适用于给定的输入:

awk 'NR==FNR{A[FNR]=$1 "  " $2 " " $3; next} {print substr($0,1,p) A[FNR] substr($0,p+length(A[FNR]))}' p=32  file2 file1

但我认为需要printfsprint格式化才能使其变得傻瓜。 所以,也许是这样的:

awk 'NR==FNR{A[FNR]=sprintf("%7.3f %7.3f %8.4f", $1, $2, $3); next} {print substr($0,1,p) A[FNR] substr($0,p+length(A[FNR]))}' p=31 file2 file1

或不在一行:

awk '
  NR==FNR {
    A[FNR]=sprintf("%7.3f %7.3f %8.4f", $1, $2, $3)
    next
  }
  {
    print substr($0,1,p) A[FNR] substr($0,p+length(A[FNR]))
  }
' p=31 file2 file1

答案 2 :(得分:0)

你可以尝试这个

paste -d' '  test4 test5 |awk '{print $1,$2,$3,$4,$5,$12,$13,$14,$9,$10,$11}'