Как я могу получить длину каждой выходной строки grep



Я очень новичок в bash scripting.
У меня есть файл трассировки сети, который я хочу разобрать. Часть файла трассировки (два пакета):



    [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


Я могу получить строку с отметкой времени и пакеты отдельно, используя grep в bash:



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


Но я не могу работать с отдельными выходными линиями после этого. Целое результат объединяется в две переменные "times"и " packets". Как я могу получить длину каждого пакета?



P.S. была бы признательна хорошая ссылка, которая действительно объясняет, как делать Программирование bash, а не просто делать примеры.
628   2  

2 ответов:

Вы действительно не хотите делать такие вещи со своей оболочкой.

Вы хотите написать настоящий парсер, который понимает формат вывода необходимой информации.

Для быстрого и грязного взлома вы можете сделать что-то вроде этого:

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

Хорошо, с простой старой оболочкой...

Вы можете получить длину строки следующим образом:

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

Там a чистый Баш решение ваших проблем!

Вы начинающий программист Bash, и вы понятия не имеете, что происходит... Давайте сделаем это шаг за шагом:

Обычным способом перебора файлов в BASH является использование цикла while read. Это объединяет while с read:

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

Каждая строка в test.txt читается в $line переменная оболочки.

Давайте возьмем следующий:

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

Это утверждение if. Всегда используйте скобки [[ ... ]], потому что они исправляют проблемы с интерполяцией оболочки. Кроме того, у них есть немного больше энергии.

=~ - это соответствие регулярному выражению. [[: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))

((...)) позволяет мне делать математику на основе целых чисел. Первый вычитает 2 из $length, а следующий делит его на 3. Теперь я могу повторить это:

echo "$length bytes"
И это наш чистый Баш ответ на этот вопрос.

Comments

    Ничего не найдено.