2015-02-06 136 views
2

我对bash脚本非常陌生。 我有一个网络跟踪文件,我想解析。跟踪文件的一部分是(两个包):如何获得grep的每条输出行的长度

[continues...] 
    +---------+---------------+----------+ 
    05:00:00,727,744 ETHER 
    |0 
    |00|03|a0|09|5c|1c|00|10|07|df|a4|20|08|00|45|00|00|38|e7|55| 

    +---------+---------------+----------+ 
    05:00:00,727,751 ETHER 
    |0 
    |00|03|a0|09|5c|1c|00|10|07|df|a4|20|08|00|45|00|00|38|e7|56|00|00|3a|01| 

    [continues...] 

对于每个数据包,我想打印时间戳和数据包的长度(十六进制值即将在下一行之后| 0头)所以输出如下:

05:00:00.727744 20 bytes 
    05:00:00.727751 24 bytes 

我可以用时间标记线和在bash分别用grep包:

times=$(grep '..\:..\:' $fileName) 
packets=$(grep '..|..|' $fileName) 

但我不能与单独的输出线工作后,那。整个结果连接在两个变量“时间”和“数据包”中。我怎样才能得到每个数据包的长度?

P.S.一个很好的参考,真正解释如何做bash编程,而不仅仅是做例子,将不胜感激。

+1

您是如何创建网络跟踪的?首先直接输出所需的值通常要容易得多,而不是写一些详细的文本,并在稍后尝试解析。 – michas 2015-02-06 17:27:09

+0

@rici,谢谢你的观点。固定 – Shervin 2015-02-06 17:31:30

+0

@michas,我下载了它。并没有自己产生。 – Shervin 2015-02-06 17:32:40

回答

1

你真的不想用你的壳做这样的事情。

你想写一个真正的解析器,理解格式输出所需的信息。

对于一个快速和肮脏的黑客,你可以做这样的事情:

perl -wne 'print "$& " if /^\d\S*/; print split(/\|/)-2, " bytes\n" if /^\|..\|/' 
+0

谢谢。这是一个很好的起点。 – Shervin 2015-02-06 18:04:06

2

好,与普通的老贝...

你可以得到这样的线的长度:

line="|00|03|a0|09|5c|1c|00|10|07|df|a4|20|08|00|45|00|00|38|e7|55|" 
wc -c<<<$line 
62 

该行有六十二个字符。将每个字符视为|00,其中00可以是任何数字。在这种情况下,最后还有一个额外的|。另外,wc -c最后包括NL

所以,如果我们取wc -c的值,并减去2,我们得到60。如果我们除以3,我们得到20这是字符数。

好了,现在我们需要一个小环,找出各种线,然后分析它们:

#! /bin/bash 

while read line 
do 
    if [[ $line =~ ^[[:digit:]]{2} ]] 
    then 
     echo -n "${line% *}" 
    elif [[ $line =~ ^\|[[:digit:]]{2} ]] 
    then 
     length=$(wc -c<<<$line) 
     ((length-=2)) 
     ((length=length/3)) 
     echo "$length bytes" 
    fi 
done < test.txt 

有一个PURE BASH解决您的烦恼!

你是个开始猛砸程序员,你不知道这是怎么回事...

让我们借此一步步时间:

循环的常见方式通过BASH文件正在使用一个while read循环。这结合了whileread

while read line 
do 
    echo "My line is '$line'" 
done < test.txt 

test.txt每一行被读入$line外壳可变。

让我们下一个:

if [[ $line =~ ^[[:digit:]]{2} ]] 

这是一个if声明。总是使用[[ ... ]]括号,因为它们解决了shell插入问题。另外,他们有更多的权力。

=~是一个正则表达式匹配。 [[:digit:]]匹配任何数字。 ^将正则表达式固定到行的开头,{2}表示我正好想要其中的两个。这表示如果我匹配以两位数开头的行(这是您的时间戳行),请执行此if子句。

${line% *}是模式过滤器。 %表示匹配(glob)最小的glob模式并将其从我的$line变量中过滤掉。我用它来删除我的线路上的ETHER-n告诉echo不要做NL。

让我们把我的elif这是一个else if子句。

elif [[ $line =~ ^\|[[:digit:]]{2} ]] 

再次,我匹配正则表达式。此正则表达式以(^)a |开头。我必须在前面放一个反斜杠,因为|是一个神奇的正则表达字符,并且\杀死了魔法。它现在只是一个管道。然后,接着是两位数字。请注意,这跳过了|0,但获得|00。现在

,我们必须做一些计算:

length=$(wc -c<<<$line) 

$(...)说,执行封闭命令,并resubstitute它放回线。 wc -c计算字符,<<<$line是我们要计算的数字。这给了我们62个字符。我们要减去2,然后用3这是接下来的两行分为:

((length-=2)) 
((length/=3)) 

((...))允许我做基于整数运算。第一个从$length减去2,下一个除以3。现在,我可以回应这个:

echo "$length bytes" 

这就是我们纯粹的Bash回答这个问题。