2

I have been stuck on this for way to long now. Tried googling and couldn't find what I was looking for.

I simply need to add all the values in an array.(array called packets) I have gotten to the point where I can add them, however when that happens the number value is not able to be called upon later in the script.

Here is the whole script, pretty simple just checking amount of packet data compared to time, aka bandwidth.

rawdata=`tcpdump -nn -S -r test.pcap | awk '{print $1" "$NF}'`
time="`echo "$rawdata" | sed -r 's/(.{15}).*/\1/'`"
starttime="`echo "$time" | awk 'NR > 1 { exit }; 1'`"
endtime="`echo "$time" | awk 'END{print}'`"
stime=`date --date="$starttime" +%s`
etime=`date --date="$endtime" +%s`
difftime="echo $(($etime - $stime))"
echo $difftime
echo $addedpackets
echo $sum
echo ------------------------------------
packets="`echo "$rawdata" | awk '{print $2}' | sed 's/[^0-9]*//g'`"
echo ------------------------------------
for i in "${packets[*]}"
do
    plus=$(printf '%d+' ${i})0
    added="echo $(($plus))"
done
echo ------------------------------------
$added
$difftime
bc -l <<< "$added/$difftime"
echo ------------------------------------
Korilic
  • 21

2 Answers2

6

Do the whole thing in awk, shell loops are not the right tool to do this kind of processing:

tcpdump -tt -nn -S -r test.pcap | awk '
  NR == 1 {start = $1}
  {total += $NF}
  END {
    duration = $1 - start
    print "total:", total
    print "duration:", duration
    print "average:", total/duration
  }'

Note how that's 2 commands running concurrently as opposed to thousands running in sequence without sharing information in your approach. This one also handles time stamps correctly.

If for some reason, you want those in shell variables, you'd do:

eval "$(
  tcpdump -tt -nn -S -r test.pcap | awk '
    NR == 1 {start = $1}
    {total += $NF}
    END {
      duration = $1 - start
      print "total=" total
      print "duration=" duration
      print "average=" total/duration
    }'
)"
echo "$total $duration $average"
2

To fill the variable packets as an array (single line to a single item) change the line 12 to:

origifs="$IFS"
IFS=$'\r\n'
packets=($(echo "$rawdata" | awk '{print $2}' | sed 's/[^0-9]*//g'))
IFS="$origifs"

to process individual items of the array you have to use @ instead of * at line 14:

for i in "${packets[@]}"

Note: Instead of backticks like `commands` it is preferred to use $(commands).

  • Originally I forgot about $IFS. Bash uses the separators from $IFS when splitting the string to the array items. By default it would split also by spaces and tabs. You want to split only by newlines. I have corrected my answer. – pabouk - Ukraine stay strong Jun 08 '15 at 11:57