如何获得grep的每个输出行的长度

时间:2015-02-06 17:17:12

标签: linux 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)

但之后我无法使用单独的输出线。整个结果在两个变量“times”和“packets”中连接在一起。如何获得每个数据包的长度?

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

2 个答案:

答案 0 :(得分: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程序员的开始,你不知道发生了什么......

让我们一步一步:

在BASH中循环文件的常用方法是使用while read循环。这将whileread

组合在一起
while read line
do
   echo "My line is '$line'"
done < test.txt

test.txt中的每一行都被读入$line shell变量。

让我们来看下一个:

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)

$(...)说要执行所附的命令并将其重新替换回该行。 wc -c计算字符数,<<<$line是我们正在计算的数字。这给了我们62个字符。我们必须减去2,然后除以3.这是接下来的两行:

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

((...))允许我进行基于整数的数学运算。第一个从$length中减去2,然后将其除以3。现在,我可以回应一下:

echo "$length bytes"

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

答案 1 :(得分:1)

你真的不想用你的shell做这些事情。

您想要编写一个真正的解析器,它能理解输出所需信息的格式。

对于快速而肮脏的黑客攻击,你可以做类似的事情:

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