2015-02-06 134 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回答這個問題。