为一系列行更改特定列中的字符串而不丢失 spaces/format
Changing string in a specific column for a range of lines without losing spaces/format
我有一个包含很多行的文件,但我希望将前 4635 行的第五列中的字符串 X
更改为另一个字符串 A
,而不会丢失原始 tabs/spacings列之间。
我希望改变(对于特定范围的行)
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([=13=], 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 行。如有任何建议,我们将不胜感激!
添加卷曲 brackets/braces 和一个 else
分支:
awk '{if (NR>=1&&NR<=4635) {split([=10=], a, FS, seps); a[5]="A"; for (i=1;i<=NF;i++) printf("%s%s", a[i], seps[i]); print ""} else {print}}' dat > tmp
没有卷曲 brackets/braces if
的主体只包含一个 split
命令。
使用 GNU awk 将第 3 个参数设为 match()
和 \s/\S
shorthand:
$ awk 'NR<4636{match([=10=],/((\S+\s+){4}).(.*)/,a); [=10=]=a[1] "A" a[3]} 1' file
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:
$ awk 'NR<4636{match([=11=],/([^[:space:]]+[[:space:]]+){4}./); [=11=]=substr([=11=],1,RLENGTH-1) "A" substr([=11=],RLENGTH+1)} 1' file
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
如果您的输入是示例中所示的固定宽度字段,那么您可以将 FIELDWIDTHS
与 GNU awk
:
结合使用
awk -v FIELDWIDTHS='21 1 *' -v OFS= 'NR<=4635{="A"} 1'
这里,第一个字段由21
个字符组成,第二个字段由1
个字符组成,其余为第三个字段。然后,您可以仅为必填行更改第二个字段。
如果输入不是固定宽度,那么,你可以使用sed
或perl
:
# GNU sed
sed -E '1,4635 s/^((\S+\s+){4})\S+/A/'
# if \s and \S isn't supported
sed -E '1,4635 s/^(([^[:space:]]+[[:space:]]+){4})[^[:space:]]+/A/'
perl -pe 's/^(\S+\s+){4}\K\S+/A/ if $.<=4635'
我有一个包含很多行的文件,但我希望将前 4635 行的第五列中的字符串 X
更改为另一个字符串 A
,而不会丢失原始 tabs/spacings列之间。
我希望改变(对于特定范围的行)
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([=13=], 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 行。如有任何建议,我们将不胜感激!
添加卷曲 brackets/braces 和一个 else
分支:
awk '{if (NR>=1&&NR<=4635) {split([=10=], a, FS, seps); a[5]="A"; for (i=1;i<=NF;i++) printf("%s%s", a[i], seps[i]); print ""} else {print}}' dat > tmp
没有卷曲 brackets/braces if
的主体只包含一个 split
命令。
使用 GNU awk 将第 3 个参数设为 match()
和 \s/\S
shorthand:
$ awk 'NR<4636{match([=10=],/((\S+\s+){4}).(.*)/,a); [=10=]=a[1] "A" a[3]} 1' file
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:
$ awk 'NR<4636{match([=11=],/([^[:space:]]+[[:space:]]+){4}./); [=11=]=substr([=11=],1,RLENGTH-1) "A" substr([=11=],RLENGTH+1)} 1' file
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
如果您的输入是示例中所示的固定宽度字段,那么您可以将 FIELDWIDTHS
与 GNU awk
:
awk -v FIELDWIDTHS='21 1 *' -v OFS= 'NR<=4635{="A"} 1'
这里,第一个字段由21
个字符组成,第二个字段由1
个字符组成,其余为第三个字段。然后,您可以仅为必填行更改第二个字段。
如果输入不是固定宽度,那么,你可以使用sed
或perl
:
# GNU sed
sed -E '1,4635 s/^((\S+\s+){4})\S+/A/'
# if \s and \S isn't supported
sed -E '1,4635 s/^(([^[:space:]]+[[:space:]]+){4})[^[:space:]]+/A/'
perl -pe 's/^(\S+\s+){4}\K\S+/A/ if $.<=4635'