Bogdan Stoica
Bogdan Stoica

Reputation: 4529

Bash loop through multiple lines of netstat command output

I'm running this command (saved the output to a text file:

netstat -ntp | grep tcp | grep EST | grep 34341

which let's say it has the output bellow (can be one single line or multiple lines):

tcp      593      0 10.10.1.11:43856       10.10.2.14:3434      ESTABLISHED     146597/daemon-
tcp      417      0 10.10.1.11:43859       10.10.2.15:3434      ESTABLISHED     146567/daemon-
tcp      317      0 10.10.1.11:43121       10.10.2.16:3434      ESTABLISHED     146582/daemon-

Here's what I came up with so far (after reading your comments):

#! /bin/bash

SLEEP=5
COUNTER=0

recvq()
{
    while read -r proto recvq x local remote state x
    do
        if [[ "$proto" == tcp && "$state" == ESTABLISHED && "$remote" =~ .*:3434 ]]
        then
            printf "%d\n" "$recvq"
        fi
    done < "$1"
}

while true; do

        (( COUNTER++ ))
        # measure recvq value
        declare -A first
        while read -r socket recvq
        do
            first[$socket]=$recvq
        done < <(recvq netstat1.txt)

        # sleep
        sleep "$SLEEP"

        # measure recvq value after sleep
        declare -A second
        while read -r socket recvq
        do
            second[$socket]=$recvq
        done < <(recvq netstat2.txt)

        [ ${#first[*]} != ${#second[*]} ] && { echo "Arrays are different size"; }

        for ii in ${!first[*]}; do
            [ "${first[$ii]}" == "${second[$ii]}" ] || { echo different element $ii; exit 1; }
        done
        echo "Arrays are identical"

done

Now I need to compare the value of recvq (before sleep) with the value of recvq (after sleep) for each of the lines found in files. If any of the initial recvq value is the same with the final recvq value then do something.

The problem is that I always get arrays are identical even if they are not!

Upvotes: 1

Views: 1313

Answers (2)

Bogdan Stoica
Bogdan Stoica

Reputation: 4529

I've figured it out in the end. Probably it would have worked just fine with associative arrays as @ceving suggested and also provided an answer but it was not working as expected.

I won't mark my own answer as the right one though. I've just posted it in case anyone might find it useful.

#/bin/bash

n1="$(cat netstat1.txt | awk '{split($5,a,":"); print a[1]"="$2}')"

sleep 5

n2="$(cat netstat2.txt | awk '{split($5,a,":"); print a[1]"="$2}')"

# check
for i in $n1; do
    ip1=`echo $i | awk '{split($i,a,"="); print a[1]}'`
    val1=`echo $i | awk '{split($i,a,"="); print a[2]}'`
    #echo $ip1 $val1

    for j in $n2; do

        ip2=`echo $j | awk '{split($j,a,"="); print a[1]}'`
        val2=`echo $j | awk '{split($j,a,"="); print a[2]}'`
        #echo $ip2 $val2

        if [ $ip1 == $ip2 ]; then
            if [ $val1 == $val2 ]; then
                echo "values: $val1 vs $val2 equal for remote ip: $ip1 => NOK! Do whatever!"
            else
                echo "values: $val1 vs $val2 dfferent for remote ip: $ip1 => OK"
            fi
        fi
    done
done

Upvotes: 0

ceving
ceving

Reputation: 23866

I would do the parsing this way:

#! /bin/bash

while read proto recvq x x port state x
do
  if [[ "$proto" == tcp && "$state" == ESTABLISHED && "$port" =~ .*:3434$ ]]
  then
    printf "%d\n" "$recvq"
  fi
done < <(netstat -ntp)

You do not need grep, cat or awk for this.

Do not do copy-paste-programming. If you have code, you want to reuse, put it in a function.

Bash has associative arrays, you can use to store the received data per socket.

#! /bin/bash

recvq()
{
  while read proto recvq x local remote state x
  do
    if [[ "$proto" == tcp && "$state" == ESTABLISHED && "$remote" =~ .*:3434$ ]]
    then
      printf "%s/%s %d\n" "$local" "$remote" "$recvq"
    fi
  done < "$1"
}

# First measure

declare -A first
while read socket recvq
do
  first[$socket]=$recvq
done < <(recvq netstat1.txt)

# Wait

sleep 10

# Second measure

declare -A second
while read socket recvq
do
  second[$socket]=$recvq
done < <(recvq netstat2.txt)

# Compare measures

for socket in "${!first[@]}"
do
  if [[ "${first[$socket]}" == "${second[$socket]}" ]]
  then
    printf "match for %s: %d\n" "$socket" "${first[$socket]}"
  fi
done

Upvotes: 1

Related Questions