首页 > 解决方案 > 为一系列行更改特定列中的字符串而不会丢失空格/格式

问题描述

我有一个包含很多行的文件,但我希望将X我的第五列中前 4635 行的字符串更改为另一个字符串A,而不会丢失列之间的原始制表符/间距。

我希望改变(对于一定范围的线路)

ATOM   2732  HN  SER X 176     181.410 174.270 311.410  0.00  0.00
ATOM   2733  CA  SER X 176     180.170 172.920 310.330  0.00  0.00
ATOM   2734  HA  SER X 176     179.860 171.950 310.720  0.00  0.00
ATOM   2735  CB  SER X 176     179.010 173.910 310.790  0.00  0.00
ATOM   2736  HB1 SER X 176     178.020 173.710 310.340  0.00  0.00
ATOM   2737  HB2 SER X 176     178.910 173.930 311.900  0.00  0.00

进入

ATOM   2732  HN  SER A 176     181.410 174.270 311.410  0.00  0.00
ATOM   2733  CA  SER A 176     180.170 172.920 310.330  0.00  0.00
ATOM   2734  HA  SER A 176     179.860 171.950 310.720  0.00  0.00
ATOM   2735  CB  SER A 176     179.010 173.910 310.790  0.00  0.00
ATOM   2736  HB1 SER A 176     178.020 173.710 310.340  0.00  0.00
ATOM   2737  HB2 SER A 176     178.910 173.930 311.900  0.00  0.00

我想出了以下代码,

awk '{if (NR>=1&&NR<=4635) split($0, a, FS, seps); a[5]="A"; for (i=1;i<=NF;i++) printf("%s%s", a[i], seps[i]); print ""}' dat > tmp

但似乎文件中的所有行现在都A在第五列,而不是第 1-4635 行。我们欢迎所有的建议!

标签: awkcurly-braces

解决方案


如果您的输入是示例中所示的固定宽度字段,那么您可以使用FIELDWIDTHSwith GNU awk

awk -v FIELDWIDTHS='21 1 *' -v OFS= 'NR<=4635{$2="A"} 1'

这里,第一个字段由21字符组成,第二个字段是1字符,其余字段是第三个字段。然后,您可以仅为所需行更改第二个字段。


如果输入不是固定宽度,则可以使用sedor perl

# GNU sed
sed -E '1,4635 s/^((\S+\s+){4})\S+/\1A/'

# if \s and \S isn't supported
sed -E '1,4635 s/^(([^[:space:]]+[[:space:]]+){4})[^[:space:]]+/\1A/'

perl -pe 's/^(\S+\s+){4}\K\S+/A/ if $.<=4635'

推荐阅读