计算分隔符之间的所有行数

计算分隔符之间的所有行数

我想计算下面示例中每个设备附加的地址数量。最好使用 awk 或 sed。

/dev/1
addr1 sometext sometext sometext
addr2 sometext sometext sometext
addr3 sometext sometext sometext
/dev/2
wwpn1 sometext sometext sometext
wwpn2 sometext sometext sometext
/dev/3
addr1 sometext sometext sometext
addr2 sometext sometext sometext
addr3 sometext sometext sometext
addr4 sometext sometext sometext
/dev/4
addr1 sometext sometext sometext

下面将为我提供一个匹配项,但除了多次手动运行命令之外,我无法为所有设备增加此匹配项:

sed -n '/\/dev\/1/,/\/dev\/2/'p 
/dev/1 
addr1 sometext sometext sometext
addr2 sometext sometext sometext
addr3 sometext sometext sometext
/dev/2

我想要做的将遍历所有设备,所以类似:

for i in `grep 'dev' somefile`; do sed -n '/$i/,/$insersecondmatchhere/'p ; done

问题是我不确定如何从命令开头的 for 循环获取 $insertsecondmatchhere 变量。

答案1

这是一种简单的方法awk;如果它看到 /dev/[0-9] 模式,它会转储任何现有的已保存模式和计数,然后重置设备和计数;否则,它会增加一个计数器。一旦到达 EOF,它就会转储保存的模式和计数。

#!/bin/awk -f
{
  if ( /\/dev\/[0-9]/ ) {
    if (dev) { print dev, count; };
    dev=$0;
    count=0;
  } else {
    ++count;
  }
}
END {
  print dev, count;
}

由于您有多个 awk 版本和 terdon 的 perl 解决方案,因此这是一个丑陋的 bash + grep + sed 解决方案,因为这似乎是您最初的方向:

#!/usr/bin/env bash

declare -a devs
devs=( $(grep ^/dev/ input) )
for ((i=0; i < ${#devs[@]} - 1; i++)); do
  start=${devs[i]}
  end=${devs[i+1]}
  start=${start//\//\\\/}
  end=${end//\//\\\/}
  count=$(sed -n "/^$start/,/^$end/p" input | wc -l)
  count=$(( count - 2 ))
  echo for ${devs[i]}, count is $count
done
start=${devs[i]}
start=${start//\//\\\/}
count=$(sed -n "/^$start/,\$p" input | wc -l)
count=$(( count - 1 ))
echo for ${devs[i]}, count is $count

主要的技巧是在将设备名称传递给sed.

答案2

像这样的东西吗?

awk -v RS="/dev/" 'NR!=1 {print "/dev/"$1":"NF-1}' file.txt

答案3

另一种awk方法:

$ awk '{if(/^\//){n=$0;}else{l[n]++}}END{for(n in l){print n" : "l[n]}}' file 
/dev/1 : 3
/dev/2 : 2
/dev/3 : 4
/dev/4 : 1

n如果当前行以/.如果没有,它将增加 的值l[n],即存储在关联数组中的l当前值的值n。这将计算每个部分的行数。读取整个文件后,在END{}块中,我们打印每个n(部分名称、dev行数)以及该部分中的行数。

你可以打高尔夫球:

awk '{/^\//?n=$0:l[n]++;}END{for(n in l){print n" : "l[n]}}' file 

在(高尔夫)Perl 中也有同样的想法:

$ perl -lne'/^\//?$n=$_:$l{$n}++;}{print"$_ : $l{$_}"for keys(%l)' file 
/dev/2 : 2
/dev/1 : 3
/dev/3 : 4
/dev/4 : 1

可以扩展到:

perl -lne 'if(/^\//){$n=$_}
           else{ $l{$n}++ } 
           END{print"$_ : $l{$_}" for keys(%l)}' file 

相关内容