在文件中的特定模式上添加标头

在文件中的特定模式上添加标头

我有一个文件,需要在 Linux 的多个位置添加标头。 “标题”是一个文件,我只能将其添加到第一行;这很好,但我现在想在多个位置添加相同的标头;特别是在找到新的 IP 地址之前。我实际上不需要带有标题的文件;在获得所有输出后,我只需通过 awk 或 sed 添加文本即可。

需要在找到新 IP 地址后准确插入标头。

该列表是可变的;例如,在 ip 192.168.10.10 处,有 3 个条目,但可能更多;例如,对于 ip 192.168.10.33,有 2 个条目,但可能更多。默认情况下端口已经排序;但 IP 地址尚未排序,但已分组。

输出看起来像:

192.168.10.10    1/1/2
192.168.10.10    1/1/3
192.168.10.10    1/1/4
192.168.10.33    1/1/2
192.168.10.33    1/1/6
192.168.10.20    1/1/6
192.168.10.20    1/1/7
192.168.10.20    1/1/10
192.168.10.20    1/1/18

我希望输出看起来像这样:

SWITCH ID        PORT    
192.168.10.10    1/1/2
192.168.10.10    1/1/3
192.168.10.10    1/1/4

SWITCH ID        PORT              
192.168.10.33    1/1/2
192.168.10.33    1/1/6

SWITCH ID        PORT
192.168.10.20    1/1/6
192.168.10.20    1/1/7
192.168.10.20    1/1/10
192.168.10.20    1/1/18

答案1

这是相当冗长的 awk 脚本,它添加了标头

NR==1 {
  print "SWITCH ID        PORT"
  print $0
  prev=$1
  next
}
$1!=prev {
  print ""
  print "SWITCH ID        PORT"
  print $0
  prev=$1
  next
}
$1==prev {
  print $0
}

将其保存到文件中。例如addheader.awk

像这样调用

awk -f addheader.awk inputfile

或者像这样

commandproducinginput | awk -f addheader.awk

脚本的解释

awk 的工作原理大致如下:

for every line of input
  for every rule
    if condition is true
      execute code block

“规则”是一对条件和代码块。

上面代码中的规则示例

NR==1 {
  print "SWITCH ID        PORT"
  print $0
  prev=$1
  next
}

NR==1就是条件。大括号中的部分{...}是代码块。

NR是一个 awk 特定变量,包含行号(准确地说是记录号)。所以NR==1仅在第一行是正确的。

在第一行我们打印标题行。然后打印实际行($0是当前行的 awk 变量)。然后记住这一行的IP地址($1是当前行第一个字段的awk变量)。然后我们说直接进入下一行,这样 awk 就不会考虑其他规则。你可以想像next一个break跳出循环for every rule

$1!=prev如果当前 IP 地址与前一个地址不匹配,则下一条规则的条件为 true。在这种情况下,我们打印一个空行。然后是标题。然后是线路本身。然后记住这个新的IP地址。然后转到下一行。

最后一条规则是“默认情况”。如果 IP 地址与之前的相同,则按原样打印该行。

next前面的规则有效地形成了一个 if else if 链。

在伪代码中,它看起来大致像这样

for every line:
  if is first line:
    print header then line
  else if IP adress is different than previous:
    print empty line then header then line
  else if IP adress is same to previous:
    print line

奖金:

以下变体是等效的

省略最后一个代码块

NR==1 {
  print "SWITCH ID        PORT"
  print $0
  prev=$1
  next
}
$1!=prev {
  print ""
  print "SWITCH ID        PORT"
  print $0
  prev=$1
  next
}
$1==prev

如果代码块丢失,默认操作是按原样打印该行。

或者省略条件但保留代码块

NR==1 {
  print "SWITCH ID        PORT"
  print $0
  prev=$1
  next
}
$1!=prev {
  print ""
  print "SWITCH ID        PORT"
  print $0
  prev=$1
  next
}
{
  print $0
}

如果条件缺失,则隐式为 true。这是可能的,因为next前面的规则有效地形成了 if else if 链。最后一条规则与最后一条 else 类似,因此不需要任何条件。

重新排列规则

$1==prev
NR==1 {
  print "SWITCH ID        PORT"
  print $0
  prev=$1
}
$1!=prev {
  print ""
  print "SWITCH ID        PORT"
  print $0
  prev=$1
}

像这样我们可以省略next.但就我的口味而言,它的可读性较差。

将公共代码提取到函数中

func common() {
  print "SWITCH ID        PORT"
  print $0
  prev=$1
  next
}
NR==1 {
  common()
}
$1!=prev {
  print ""
  common()
}
$1==prev

请注意,所有变量在 awk 中都是全局的。

相关内容