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

How can I get the length of each output line of grep

我对 bash 脚本编写还很陌生。 我有一个要解析的网络跟踪文件。跟踪文件的一部分是(两个数据包):

    [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 header 后下一行的十六进制值),因此输出将如下所示:

    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 编程,而不仅仅是举例,我们将不胜感激。

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

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

对于快速而肮脏的 hack,您可以这样做:

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

好吧,用普通的旧 shell...

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

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} ]]

同样,我正在匹配一个正则表达式。这个正则表达式以 (The ^) a | 开头。我必须在前面加一个反斜杠,因为 | 是一个神奇的正则表达式字符,而 \ 会破坏魔法。现在只是一根管子。然后,后面跟着两位数字。请注意,这会跳过 |0 但会捕获 |00.

现在,我们要做一些计算:

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

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

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

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

echo "$length bytes"

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