awk中字段替换后的输出字段分隔符

4

当在awk中修改特定字段后,输出字段分隔符的信息是否总是丢失?如果有多个字段分隔符并且想要恢复它们,会发生什么?

例如,假设我有一个包含以下内容的简单文件example

a:e:i:o:u

如果我只运行一个 awk 脚本,该脚本考虑输入字段分隔符,并打印文件中的每一行,例如执行

awk -F: '{print $0}' example

我将查看原始代码。但是,如果我直接修改其中一个字段,例如使用

awk -F: '{$2=$2"!"; print $0}' example

我没有收到原始行的修改版本,而是看到了默认空格分隔符分隔的字段,即:

a e! i o u

如果我指定OFS,就可以得到原始版本的修改版,例如:

awk -F: 'BEGIN {OFS=":"} {$2=$2"!"; print $0}' example

在某些情况下,可能会有多个潜在的字段分隔符,但是如果有多个分隔符的情况下,是否有一种简单的方法来恢复原始的分隔符?
例如,如果“example”既有“:”又有“;”作为分隔符,我可以使用“-F”:|;”来处理文件,但OFS将无法足以恢复原始分隔符的相对位置。
更明确地说,如果我们切换到包含“example2”的内容。
a:e;i:o;u

我们可以使用
awk -F":|;" 'BEGIN {OFS=":"} {$2=$2"!"; print $0}' example2

使用-F"[:;]"选项来获取

a:e!:i:o:u

但是我们已经失去了“:”和“;”之间的区别,如果我们能够恢复,这种区别将被保持。
a:e!;i:o;u

1
这个问题是这里的少有好问题之一。为什么不简单地使用“-F'[:;]'”来添加一个不起作用的示例呢?这将使问题完美 - 我认为。 - hek2mgl
1
添加了显式示例 - borrible
1
@MichaelVehrs 这并不难,只是不必要地消耗时间和内存。 Awk 应该是非常高效的,并且实际上也确实如此。如果我们需要存储与每行上每个 FS 匹配的字符串,则会为几乎从不需要的功能添加周期。当然,您可以添加标志来打开/关闭它,但是字段拆分代码必须检查标志,而且如果没有引用标志,则无法确定代码的作用。如果您想要执行某项操作,您只需提供一个可调用的函数即可,这样更简单、更清晰、更高效。 - Ed Morton
1
另外,由于这是一般情况下分割字符串的有用功能,您需要split()函数中提供它。一旦您为split(<任何字符串>,...)提供了该功能,您就可以将其用于split($0,...),因此没有必要以某种其他方式专门为$0复制该功能,特别是考虑到该功能很少使用。 - Ed Morton
再次强调,我并不是说编写代码很难,而是在执行代码时会增加一些循环。填充数组并不是免费的。我感觉自己在重复,所以我结束了,但如果你愿意,请随意与维护gawk的人员探讨 - 他们参与comp.lang.awk新闻组,我相信他们会乐意回答问题。 - Ed Morton
显示剩余4条评论
1个回答

5

您需要使用GNU awk来作为split()的第4个参数,该参数将保存分隔符,就像RT对于RS所做的那样:

$ awk -F'[:;]' '{split($0,f,FS,s); $2=$2"!"; r=s[0]; for (i=1;i<=NF;i++) r=r $i s[i]; $0=r} 1' file
a:e!;i:o;u

由于将匹配FS的字符串自动填充到一个数组中会占用大量时间和内存,所以没有自动填充的数组。相反,GNU awk提供了split()的第4个参数,以便在需要时自行完成。这是几年前在comp.lang.awk新闻组中经验丰富的awk用户和gawk提供者之间进行长时间讨论后达成的共识,认为这是最佳方法。

请参见https://www.gnu.org/software/gawk/manual/gawk.html#String-Functions上的split()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接