用 awk 替换列,并保留格式

问题描述 投票:0回答:4

这是文件

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.pdb
列替换
a.xyz
的第 6,7 和第 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 

但它不保留格式。

replace awk format
4个回答
11
投票

这正是 GNU awk 中 split() 的第四个参数的发明目的:

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

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

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

因此 1、2 和 4 使用

sub
来替换,这不是防水解决方案,因为早期的字段可能会干扰并且它使用正则表达式而不是字符串(因此正则表达式点恰好与实际点匹配),但是有了这个特定的输入,它可能会成功..

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

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

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

但我认为需要类似

printf
sprint
的格式才能使其万无一失。 所以,也许是这样的:

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

0
投票

你可以试试这个

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

0
投票

这是一个 POSIX awk 解决方案。没有 gawk 的扩展

split()
,我们必须自己跟踪间距:

awk '
  NR==FNR {fld1[NR]=$1; fld2[NR]=$2; fld3[NR]=$3; next}
  {
    tmp = $0
    n = 0
    out = ""
    for (i = 1; i < NF; i++) {
      tmp = substr(tmp, n)
      spacing = substr(tmp, 1, index(tmp, $i) - 1)
      n = length(spacing $i) + 1
      out = out spacing
      if (i == 6) out = out fld1[FNR]
      else if (i == 7) out = out fld2[FNR]
      else if (i == 8) out = out fld3[FNR]
      else out = out $i
    }
    $0 = out substr(tmp, n)
  }
  1
' a.xyz a.pdb
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

它会跟踪每个字段之间的间距,以便在替换后可以重新组装。

首先,我们将临时变量

tmp
设置为整条线
$0
,并初始化位置跟踪器
n
和最终组装
out
。然后我们循环遍历 awk 已经解析的每个字段。循环第一次运行中的第一个
tmp
赋值不会执行任何操作,因为
n
为零。然后我们将
spacing
设置为
tmp
位于我们所在字段的第一个实例之前的部分(其值为
$i
)。接下来,
n
更新到新位置,以便我们可以在下一次迭代中缩小
tmp
out
获得我们刚刚保存的间距。

现在,我们终于可以执行您想要执行的操作了。我们检查

$6 = fld1[FNR]
并将值附加到
i
,而不是
out
。如果它不是我们想要的替换之一,我们只需附加原始值。

循环之后,我们将

$0
分配给准备好的
out
,并且任何尾随字段分隔符可能会持续存在(可能什么也没有)。独立的
1
子句会导致其打印。


您很可能可以在运行更简单的 awk 代码后重新格式化输出。只需通过管道即可

column -t
:

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 |column -t
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

另请参阅我自己的 columns 脚本,我更喜欢它而不是

column -t
,因为它更强大并且可以处理颜色和选项卡。

© www.soinside.com 2019 - 2024. All rights reserved.