替换固定宽度文件中的单个条目

Replacing Individual Entries in Fixed Width File

我有一个固定宽度的数据文件,如下所示:

ATOM   6181  H4  BGLC    2      -6.078 -11.556   0.599  1.00  0.00
ATOM   6182  O4  BGLC    2      -5.410 -10.816   2.307  1.00  7.76
ATOM   6183  C6  BGLC    2      -8.313 -11.233   1.955  1.00  8.41
ATOM   6184  H61 BGLC    2      -9.308 -11.734   2.225  1.00  0.00
ATOM   6185  H62 BGLC    2      -8.302 -10.340   2.573  1.00  0.00
ATOM   6186  O6  BGLC    2      -8.412 -11.033   0.547  1.00  8.44
ATOM   6187  HO6 BGLC    2      -7.623 -10.829   0.055  1.00  0.00
ATOM   6188  C1  BGLC    3      -4.821  -9.797   1.481  1.00  7.45
ATOM   6189  H1  BGLC    3      -5.419  -9.613   0.596  1.00  0.00

我正在尝试用其他变量 chargeradius 替换最后两列。我尝试使用 cut 来挑选出该行的前 54 个字符(前 8 列),然后使用 echo 将 chargeradius 添加到末尾,如下所示:

newline=$(echo $(echo $pqratomline | cut -c 1-54) $charge $radius)

其中 pqratomline 是一个字符串,等于文件中的特定行。但是,echo 会去除多余的空格,从而丢弃固定宽度的列。

有没有人对如何在不使用 echo 的情况下执行此操作或如何防止 echo 删除多余的空格有任何建议?

编辑: 我想要看起来像这样的东西(只显示前几行):

ATOM   6181  H4  BGLC    2      -6.078 -11.556   0.599  0.0900  1.3400
ATOM   6182  O4  BGLC    2      -5.410 -10.816   2.307 -0.6500  1.7650

相反,我得到:

ATOM 6181 H4 BGLC 2 -6.078 -11.556 0.599 0.0900 1.3400
ATOM 6182 O4 BGLC 2 -5.410 -10.816 2.307 -0.6500 1.7650

作为替代方案,您可以使用 printf 而不是 echo,因为 printf 具有更好的行为,您还可以调整每个打印变量的宽度:

$ echo "$a"
ATOM   6179  HO3 BGLC    2      -3.020 -13.471   0.981  1.00  0.00

$ charge="2.22";radius="2.22"

$ newline=$(printf '%s%6s%6s\n' "$(echo "$a" | cut -c 1-54)" "$charge" "$radius");echo "$newline"
ATOM   6179  HO3 BGLC    2      -3.020 -13.471   0.981  2.22  2.22

printf 中的 %6s 格式规定要打印的变量宽度为 6 个字符。

同样:

$ echo "$a"
ATOM   6179  HO3 BGLC    2      -3.020 -13.471   0.981  1.00  0.00

$ charge="0.0900";radius="1.3400"

$ newline=$(printf '%s%12s%12s\n' "$(echo "$a" | cut -c 1-54)" "$charge" "$radius");echo "$newline"
ATOM   6179  HO3 BGLC    2      -3.020 -13.471   0.981      0.0900      1.3400

您可以根据需要调整新字段宽度的值(%12s 以上)。

awk 的一个问题是,除非您特别注意准备输出格式,否则它会删除空格,从而破坏您的固定宽度间距。

awk -v charge="$charge" -v radius="$radius" '
  {
    printf "%54s%8.4f%8.4f\n", substr([=10=],1,54), charge, radius
  }
' input.txt

这使用 awk 的 -v 选项将环境变量插入 awk 脚本。

当然,您可以在 bash 中执行此操作,并使用参数扩展来去除不需要的行部分...

while read line; do

  lhs=${line:0:54}    # The first 54 characters...
  rhs=${line:54}      # in case you need these for later...

  printf '%s%8.4f%8.4f\n' "$lhs" "$charge" "$radius"

done < input.txt

假设您的 charge 和 radius 变量不包含反向引用或 /s 或 sed 可能关心的任何其他内容:

$ charge=7
$ radius=2.5

$ sed 's/[^ ]*\( *\)[^ ]*$/'"$charge"''"$radius"'/' file
ATOM   6181  H4  BGLC    2      -6.078 -11.556   0.599  7  2.5
ATOM   6182  O4  BGLC    2      -5.410 -10.816   2.307  7  2.5

请注意,您发布的预期输出不遵循与输入相同的固定宽度布局(它保留了最后 2 个字段之间的间距,但扩展了每个字段占用的 space),因此也没有以上解决方案。