计算模式匹配之前/之后的总行数


9

我的IP地址列表很长,但顺序不一。我需要查找特定IP地址之前/之后有多少个IP地址。我该如何实现?


您有重复的IP吗?
cuonglm 2014年

否。所有IP地址都是唯一的。
Mandar Shinde 2014年

IP地址之前/之后意味着什么?特别是,您同时拥有IPv4和IPv6地址吗?他们如何比较?
vinc17 2014年

您需要对文件排序吗?
cuonglm 2014年

2
@ vinc17-文件仅包含IP地址(IPv4),不包含其他数据。如果总共有1000个IP地址,并且在第300个位置找到了匹配项,则意味着匹配项之前有299行,而匹配项之后有700行。
Mandar Shinde 2014年

Answers:


8

匹配前后的行数,包括匹配(即,如果要排除匹配,则需要从结果中减去1):

sed -n '0,/pattern/p' file | wc -l
sed -n '/pattern/,$p' file | wc -l

但这与IP地址无关。


4

也许最简单的是

sed -n '/pattern/{=; q;}' file

感谢@JoshepR指出错误


这只是打印发生图案的行号。
Joseph R.

@JosephR。-不,它会打印一个匹配发生的行号。
mikeserv 2014年

@mikeserv我知道,但是OP 指定 IP地址是唯一的。OP也不希望发生匹配的行号;他们想要的行数发生的模式之前之后的行数。
Joseph R.

@JosephR-达到这些计数的最快方法是计算行号-我可能会直接将其通过管道发送给dc
mikeserv 2014年

@mikeserv我并不是说这个答案的信息没有用,我只是说这段代码本身并不能满足OP的要求。
Joseph R.

3

我做了两种方式,尽管我认为我最喜欢这种方式:

: $(( afterl=( lastl=$(wc -l <~/file) ) - 2 -
  $(( beforel=( matchl=$(sed -n "/$IP/{=;q;}" <~/file) ) - 1
)) ))
for n in last match afters befores
do  printf '%s line%s :\t%d\n' \
        "${n%s}" "${n##*[!s]}" $((${n%s}l))
done

这会将所有这些保存为当前的shell变量-并在随后的for循环中对其求值以进行输出。它使用来计数文件中的总行,wc并使用来获取第一个匹配的行号sed

其输出:

last line :     1000
match line :    200
after lines :   799
before lines :  199

我也做了:

sed -n "/$IP/=;\$=" ~/file |  
tr \\n \  | { 
IFS=' ' read ml ll 
printf '%s line%s:\t%d\n' \
    last '' $((ll=${ll##* }))
    match '' $ml \
    after s "$((al=ll-ml-1)) \ 
    before s $((bl=ml-1))
}

sed仅打印匹配的行号和最后一行的行号,然后tr将中间的行号转换\n,并将结果read的第一个读sed入,$ml并将所有其他结果读入$ll。可能的多个匹配情况是通过$ll在以后再次设置时从扩展中除去最后一个结果以外的所有结果来处理的。

其输出:

last line :     1000
match line :    200
after lines :   799
before lines :  199

两种方法都通过以下方式在生成的文件上进行了测试:

IP='some string for which I seek' 
for count in 1 2 3 4 5 
do  printf '%.199d%s\n' 0 "$IP" 
done | tr 0 \\n >~/file 

通过行号:

  1. 设置搜索字符串
  2. 循环五次以确保将有多个匹配项
  3. 先打印199个零,然后"$IP"再显示一条\newline
  4. 管道输出到tr-将零转换为\n粗线,然后转换为~/file

2

这是执行此操作的一些Perl代码:

perl -ne '
     if(1 .. /192\.168\.1\.1/) { $before++ }
     else                      { $after++  }
     $before--; # The matching line was counted
     END{print "Before: $before, After: $after\n"}' your_file

这将对包含IP的行之前和之后的行总数进行计数192.168.1.1。替换为所需的IP。

仅使用Bash:

before=0
match=0
after=0
while read line;do
    if [ "$line" = 192.168.1.1 ];then
        match=1
    elif [ $match -eq 0 ];then
        before=$(($before+1))
    else
        after=$(($after + 1))
    fi
done < your_file
printf "Before: %d, After: %d\n" "$before" "$after"

BASH是首选。
Mandar Shinde 2014年

2
@Joseph R .:为什么不使用它$.而不是计数器?
cuonglm 2014年

@Gnouc我当然可以。我只是觉得这是不是设置更具可读性$after$. - $before
Joseph R.

不,我是说:如果匹配,请打印$. - 1,保存$.$tmp。结束打印$. - $tmp。因此,我们不需要之前和之后的计数器。当然,它的可读性不如您。
cuonglm 2014年

@MandarShinde请查看编辑。我添加了一个纯Bash答案。
Joseph R.

2

我正在尝试以下命令,这些命令有些复杂,但是会给出准确的结果:

后:

a=$(cat file | wc -l) && b=$(cat -n file | grep <Pattern> | awk '{print $1}') && echo "$a - $b" | bc -l

之前:

echo "`cat -n file | grep <Pattern> | awk '{print $1}'`-1" | bc -l

2

一个awk解决方案之前和最后一场比赛后,报告行数

awk '/192\.168\.1\.1/{x=NR};{y=NR} END{printf "before-%d, after-%d\n" , x-1, y-x}'  file

1

Grep具有可计算发现特定图案次数的功能。如果您使用的-c命令将这样做。使用-cand -v命令,它将计算与特定模式不匹配的次数

例:

grep -c -v <pattern> file

因此,如果您尝试以下操作:

grep -c -v 192.168.x.x file.log 那应该工作。


这计算目标IP的出现次数。这不是OP所要求的。
Joseph R.

我刚刚对其进行了编辑,如果他要求对特定IP之前和之后的所有其他IP进行计数,则该编辑应该对他有用。
ryekayo 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.