Reputation: 751
I have am having a bit of difficulty understanding weird behaviour of my script. First, here is the script in question:
processor_usage_script.sh
#!/bin/bash
# This script will be used to obtain and store processor usage information for given ip
function join { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
retrieve_processor_usage()
{
# retrieve current id in host table for current IP address
current_id=($(mysql -u root -phassan01 -D honours_project -e "SELECT id FROM hosts WHERE host_ip='$1'" -s -N))
# get host os, as windows has different MIB OID for processor usage
host_os=$(mysql -u root -phassan01 -D honours_project -e "SELECT host_os FROM host_descriptions WHERE host_id='$current_id'" -s -N)
# take host os value and break it down to see if the os is windows based
curr_host_os_temp=$(echo "$host_os" | sed 's/^.*\(Windows.*\)/\1/')
curr_host_os=$(echo $curr_host_os_temp | tr -s ' ' | cut -d\ -f1)
if [ "$curr_host_os" == "Windows" ]; then
echo $( date '+%Y-%m-%d_%H-%M-%S' ) " - Host $1 is a $curr_host_os machine" >> logs/$( date '+%Y-%m-%d' )
IFS=$'\n'
var=($(snmpwalk -v1 -c public -Ovq -r 1 $1 HOST-RESOURCES-MIB::hrDeviceType))
# Set up a counter value that I will use to get the values for the porcessor usage
local count=1
# create array to keep counts that will be used to get processor usage
local count_array=()
for i in "${var[@]}"; do
p=$(echo "$i" | sed 's/^.*\(hrDeviceProcessor\)/\1/')
if [[ "$p" == "hrDeviceProcessor" ]]; then
count_array=("${count_array[@]}" "$count")
count=$((count+1))
else
count=$((count+1))
fi
done
# declare processor usage array
processor_usage=()
# loop through count array and get processor usage
for i in "${count_array[@]}"; do
p_usage=$(snmpget -v1 -c public -r 1 -Ovq $1 .1.3.6.1.2.1.25.3.3.1.2.$i)
#processor_usage=("${processor_usage[@]}" "$p_usage");
processor_usage+=("$p_usage");
done
# make processor usage comma separated
processor_usage_comma_separated=$(join , "${processor_usage[@]}")
#proces
sor_usage_comma_separated=$(printf "%s," "${processor_usage[@]}")
# pass values to log that values for processor usage has been inserted
echo $( date '+%Y-%m-%d_%H-%M-%S' ) " - Inserted into database processor usage details for $1 -- Processor Usage - $processor_usage_comma_separated" >> logs/$( date '+%Y-%m-%d' )
echo "$processor_usage_comma_separated"
# insert value into database under host_processor_usage_windows
mysql -u root -phassan01 -D honours_project -e "INSERT INTO host_processor_usage_windows (id,host_id,system_time,processor_usage) VALUES ('','$current_id',NOW(),'$processor_usage_comma_separated')"
echo $1
else
# declare base ssCpuRaw variable
ssCpuRaw=".1.3.6.1.4.1.2021.11"
# use IP address to retrieve raw kernel usage (ssCpuRawKernel -- .1.3.6.1.4.1.2021.11.55.0)
kernel_space_time=$(sudo snmpget -v1 -c public -Oqv -r 1 $1 $ssCpuRaw.55.0)
# use IP address to retrieve raw user space usage (ssCpuRawUser -- .1.3.6.1.4.2021.11.50.0)
user_space_time=$(sudo snmpget -v1 -c public -Oqv -r 1 $1 $ssCpuRaw.50.0)
# use IP address to retrieve raw IO space usage, i.e. time spent waiting for IO (ssCpuRawUser -- .1.3.6.1.4.2021.11.54.0)
io_space_time=$(sudo snmpget -v1 -c public -Oqv -r 1 $1 $ssCpuRaw.54.0)
ssor_usage=("${processor_usage[@]}" "$p_usage");
processor_usage+=("$p_usage");
done
# make processor usage comma separated
processor_usage_comma_separated=$(join , "${processor_usage[@]}")
#processor_usage_comma_separated=$(printf "%s," "${processor_usage[@]}")
# pass values to log that values for processor usage has been inserted
echo $( date '+%Y-%m-%d_%H-%M-%S' ) " - Inserted into database processor usage details for $1 -- Processor Usage - $processor_usage_comma_separated" >> logs/$( date '+%Y-%m-%d' )
echo "$processor_usage_comma_separated"
# insert value into database under host_processor_usage_windows
mysql -u root -phassan01 -D honours_project -e "INSERT INTO host_processor_usage_windows (id,host_id,system_time,processor_usage) VALUES ('','$current_id',NOW(),'$processor_usage_comma_separated')"
echo $1 retrieve current id in host table for current IP address
current_id=($(mysql -u root -phassan01 -D honours_project -e "SELECT id FROM hosts WHERE host_ip='$1'" -s -N))
if [ -n "$kernel_space_time" ] && [ -n "$user_space_time" ] && [ -n "$io_space_time" ]; then
echo $( date '+%Y-%m-%d_%H-%M-%S' ) " - Inserted into database processor usage details for $1 -- Kernel space: $kernel_space_time, User space: $user_space_time, IO space: $io_space_time" >> logs/$( date '+%Y-%m-%d' )
# insert values into database
mysql -u root -phassan01 -D honours_project -e "INSERT INTO host_processor_usage (id,host_id,system_time,kernel_space_time,user_space_time,io_space_time) VALUES ('','$current_id',NOW(),'$kernel_space_time','$user_space_time','$io_space_time')"
fi
fi
}
retrieve_processor_usage $1
What this script is suppose to do is take a given IP address and do an snmpget after retrieve the correct MIB id. The IP address is then used to do another retrieval using another script. When executed a lone this script works fine. The IP address passed in is the same at the end of execution of this script. However when run in the context it was designed for it fails. Here is the the context in which it executes:
main.sh
...
SECONDS=300
while true
do
for i in "${active_ip_open_161[@]}"
do
. ./processor_usage_script.sh $i
. ./memory_usage_script.sh $i
. ./bandwidth_usage_script.sh $i
done
sleep $SECONDS
done
...
In the actual execution context a given IP is first passed into proceessor_usage_script.sh, then memory_usage_script.sh and so forth. In this case, after execution of processessor_usage_script.sh, a value of 7 gets returned and passed to the subsequent scripts. I don't understand why it is doing this, but I do believe I have narrowed it down to the execution of the MySQL statement. I was wondering if I could get help debugging why it is failing.
Upvotes: 2
Views: 335
Reputation: 437176
Siguza's comment on the question hints at the problem:
By sourcing[1]
the scripts you invoke (. <script> ...
), these script's variables modify / add to the calling shell's variables.
Specifically, since $i
is modified both in the calling script and inside processor_usage_script.sh
, the next sourcing command, . ./memory_usage_script.sh $i
, will pass whatever processor_usage_script.sh
set $i
to - not the original $i
loop-variable value.
Solution options:
Use distinct variable names to avoid collisions.
Preferably, do not use sourcing - pass any information the helper scripts need via arguments, and use stdout output to pass information out.
./processor_usage_script.sh "$i"
(no preceding .<space>
)Siguza also suggests double-quoting your variable references, which I've done above ("$i"
), which is alway a good idea to ensure that the values aren't interpreted by the shell - even though in the case at hand (IP addresses) it happens to make no difference.
[1] Note that the linked POSIX spec. simply calls the .
builtin utility dot, whereas Bash uses the term sourcing (and also allows use of source
in lieu of .
). Either way, the crucial aspect is that the specified script is loaded into the calling shell's context and therefore allows that script to modify the calling script's environment (variables, functions, aliases, shell option states, ...) - by contrast, direct invocation of a script causes it to run in a child process that has no impact on the calling shell's environment.
Upvotes: 4