Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bad array subscript

Tags:

arrays

bash

shell

I'm relatively new to Shell and I've been trying to use arrays in Shell and it's not working well. I'm trying to write a script to suspend OpenVZ containers should they hit a certain bandwidth threshold over a period of time.

My script:

#!/bin/bash
#Thresholds are in bytes per second and count1 must > count2
LOGDIR="/var/log/outbound_ddos"
SECS=10
THRESHOLD1=65536000
COUNT1=10
THRESHOLD2=117964800
COUNT2=2

while [ 1 ]
do
    for veid in $(/usr/sbin/vzlist -o veid -H)
    do      
        # Create the log file if it doesn't already exist
        if ! test -e $LOGDIR/$veid.log; then
            touch $LOGDIR/$veid.log
        fi

        # Parse out the inbound/outbound traffic and assign them to the corresponding variables     
        eval $(/usr/sbin/vzctl exec $veid "grep venet0 /proc/net/dev"  |  \
            awk -F: '{print $2}' | awk '{printf"CTOUT=%s\n", $9}')

        # Print the output and a timestamp to a log file
        echo $(date +%s) $CTOUT >> $LOGDIR/$veid.log

        # Read last 10 entries into arrays
        i=0
        tail $LOGDIR/$veid.log | while read time byte
        do
            times[$i]=time; bytes[$i]=byte
            let i++
        done

        # Sanity checks and calculations
        for (( i=0; i<COUNT1; i++ ))
        do
            # Sanity check on the time
            if (( times[$i] > times[$i - 1] + $SECS + 10 ))
                then continue
            fi

            # Calculate differences
            let "diff[$i] = bytes[$i+1] - bytes[$i]"
        done

        # Work out thresholds and suspend where necessary
        # Higher threshold first
        t2=0
                for (( i=COUNT1-1; i>=0; i-- ))
                do
                        if [ ! diff[$i] ]
                                then continue
                                else
                                        if (( bytes[$i] < THRESHOLD1 * SECS + bytes[$i-1] + 1 ))
                                                then continue
                        else let t2++
                                        fi
                        fi
                done
        #Lower threshold last
        t1=0
        for (( i=COUNT1-1; i>=0; i-- ))
        do
            if [ ! diff[$i] ]
                then continue
                else
                    if (( bytes[$i] < THRESHOLD1 * SECS + bytes[$i-1] + 1 ))
                        then continue
                        else let t1++
                    fi
            fi
        done

        # Suspend where necessary
        if (( ($t2 >= $COUNT2) || ($t1 >= $COUNT1) ))
            then vzctl stop veid
        fi
    done
    sleep $SECS
done

And the errors:

script.sh: line 38: times: bad array subscript
script.sh: line 54: bytes: bad array subscript
script.sh: line 67: bytes: bad array subscript

I've tried several variations of the array subscript but I can't seem to get rid of those errors.

like image 985
James Avatar asked Apr 20 '13 12:04

James


1 Answers

So on line 38,

if (( times[$i] > times[$i - 1] + $SECS + 10 ))

would refer to times[-1] once during the iteration. Negative indices are only very recently part of bash arrays, so that is most likely why you are getting the error.

Likewise with lines 54 and 67 you're hitting a negative array subscript once. Adjust your loops to avoid [0 - 1].

like image 140
kojiro Avatar answered Nov 16 '22 01:11

kojiro