【问题标题】:Make awk keep the input formating spacing intact for output使 awk 保持输入格式化间距不变以进行输出
【发布时间】:2013-03-08 20:16:27
【问题描述】:

我想打印仅修改了某些特定列的输入列 ASCII 数据文件。 如果我使用 awk 修改列(例如:$NF=99),当我最终给出“print $0”命令时,它会正确打印输出,但其他列的所有空格填充、格式等都消失了。 (它们基本上都被 OFS 取代了)。

有什么方法可以让 awk 打印完全相同的输入,并且只在指定的列中进行更改? 我需要将此输出提供给另一个具有非常严格的读取格式的 fortran 代码。所以我不能改变行的格式。

如果 awk 不是我应该为此目的使用的软件,您有什么建议?


更新:示例:

连续输入条目。

0 0 0 0 0 0 0  1936 24170  2536  1987 24094  2543  2037 24153  2550  2088 24202  2557 27 24 24.5 10000.0    0.31     0.0 10000.0     0.0     0.0     0.0    0.65

我想将该条目转换为

0 0 0 0 0 0 0  1936 24170  2536  1987 24094  2543  2037 24153  2550  2088 24202  2557 27 24 24.5 10000.0 10000.0 10000.0 10000.0 10000.0 10000.0 10000.0 10000.0

重要的是保持其他列的间距和位置不变。


为了完成我的任务,我能做的最接近的事情是以下命令。

gawk '{output=$0;for (i=0;i<8;i++){output=substr(output,0,97+8*i-1)"10000.0"substr(output, 97+8*(i+1)-1)}; print output}'

【问题讨论】:

  • 如果您能具体一点,包括一个示例输入文件以及预期输出,将会有所帮助。
  • 这个例子有点帮助,但还不清楚:你只是想用10000.0替换最后8列数字吗?
  • 与上面的示例不同,我想替换为给出字段(如 $10、$13 等)。我会注意不要让它插入任何大于可用空格填充的空间。

标签: awk


【解决方案1】:

如果字段是固定宽度的,您是否考虑过不按字段编号而是按列编号进行更改?您可以通过 substr() 在 awk 中执行此操作,也可以使用 cut。

例如假设您想要的字段始终在第 56-60 列中,您可以这样做 打印 substr($0,1,55) "文本!" substr($0,61);

【讨论】:

  • 因为要替换的字段每次都会改变。我想我应该制作一个查找表,将每个相应字段的位置存储在列中,并按照您提到的那样替换。谢谢,
【解决方案2】:

您对自己在做什么并不太具体,所以我不能在这里具体说明。也就是说:

听起来您需要做的是让您的代码直接修改$0,而不是选择一个字段。 sub()gsub() 可能对您有用,或者您可以使用 match()“查找”一个字段。

【讨论】:

  • 感谢您的建议。我添加了一个示例。
【解决方案3】:

使用 GNU awk,以下是如何将第三个字段替换为单词“replacement”:

$ cat file
field1      field2           field3    field4

$ gawk -v field=3 -v text="replacement" '{ print gensub("(^[[:space:]]*([^[:space:]]+[[:space:]]+){" field-1 "})[^[:space:]]+", "\\1" text, "") }' file
field1      field2           replacement    field4

在其他 awk 中,您可以使用 sub()s 或 match()+substr()s 做同样的事情。

要保持字段结束位置,假设替换文本小于或等于原始长度加上它前面的空格:

$ cat file
field1      field2           field3    field4
  field1      field2           field3    field4

$ awk -v fieldNr=3 -v text="replacement" -f tst.awk file
field1      field2      replacement    field4
  field1      field2      replacement    field4

$ cat tst.awk
BEGIN {
    preFld="^([[:space:]]*[^[:space:]]+){" fieldNr-1 "}"
}
{
    match($0,preFld)
    head = substr($0,RSTART,RLENGTH)

    match($0,preFld "[[:space:]]*[^[:space:]]+")
    field = substr($0,RSTART+length(head),RLENGTH-length(head))

    printf("%s% *s%s\n", head, length(field), text, substr($0,RSTART+RLENGTH))
}

有关该主题和不同解决方案的更多信息,请尝试使用 GNU gawk“patsplit()”函数和/或 FIELDWIDTHS 变量。

【讨论】:

  • 谢谢你的例子。我想保持替换右侧的列位置也与输入完全相同。我在上面的问题中添加了一个示例以说明问题。
  • 您说要保留间距和位置,但除非替换字段与原始字段的宽度相同,否则您不能同时拥有两者。看起来您真正想要的是保持位置,而不是与您发布的问题完全不同的间距。
  • 我会注意不要插入任何大于该字段允许的空间的内容。通过“保留间距”,我的意思是我没有改变的其他列的间距。 [这部分问题已经通过您使用 substr() 的建议解决]
猜你喜欢
  • 2023-03-24
  • 1970-01-01
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-01
  • 1970-01-01
相关资源
最近更新 更多