我有一个文件,我想更改第 400 行到第 600 行上的一个字符。该字符恰好是每行的第 22 个字符。它也是第 5 列,因此我尝试了以下操作:
awk '{if (NR>=400 && NR <=600) $5="B"; print}' file.txt
问题是,每列之间有精确数量的空格,当我这样做时,这些空格会被单个空格替换。我怎样才能更改单个字符而不触及行范围内的任何其他字符(包括分隔符)?
答案1
优雅的方法是将每个字符视为一个字段。如果您将 FS 设置为空字符串,awk 将以这种方式拆分它们。然后您可以将第 22 个字段设置为您希望的值。只需记住将 OFS 也设置为空字符串,以便输出中的所有字符之间没有空格(默认 OFS)。
awk -vFS="" -vOFS="" 'NR==400,NR==600 {$22="B"}; {print}'
显然,这个方法会对超出范围的行进行不必要的拆分。我们可以在第 400 行之前设置字段分隔符,在第 600 行之后设置字段分隔符。但是,既然有 substr(),为什么还要在这里拆分呢?让我们用前 21 个字符 + “B” + 原始行的其余部分创建一个字符串,用于重要的行。
awk '{s=$0}; NR==400,NR==600 { s=substr($0,1,21) "B" substr($0,23)}; {print s}'
(没有 s 也可以做到这一点,只需为 $0 分配其新值,但是当我们分配 $0 时,它会根据规则重新拆分,现在没有理由为该步骤牺牲速度。)
答案2
您还可以使用sed
:
sed -r '400,600s/(.{21}).(.*)/\1B\2/' file.txt