#!/bin/bash
function display_help
{
cat << EOF
${0##*/} [-c column_index] [-e] [-f data_file] [-h] [-p] [-r refresh_rate_value] [-t column_title]
-c column_index
You can use this parameter several times and you must use it as many times than column_title parameter.
column_index starts at one.
-e
Erase existing data file.
Non-erase (append) mode by default.
-f data_file
data_file will contain data to be plotted.
If you omit this parameter, a temporary data file (provided by mktemp command) will be used.
-h
This short help message.
-p
Enable data producer.
Disabled by default.
-r refresh_rate_value
Refresh rate (in seconds) for plotting data.
One second by default.
-t column_title
You can use this parameter several times and you must use it as many times than column_index parameter.
Title used as name for plotting data.
EOF
}
function parse_option
{
local current_option
while [ ! $# -lt ${OPTIND} ]
do
while getopts :c:ef:hpr:t: current_option
do
case ${current_option} in
c)
g_column_container+=("${OPTARG}")
;;
e)
g_erase_data='true'
;;
f)
g_data_file=${OPTARG}
;;
h)
display_help
exit
;;
p)
g_enable_producer='true'
;;
r)
g_period=${OPTARG}
;;
t)
g_title_container+=("${OPTARG}")
;;
\?)
echo "invalid option: -${OPTARG}" >&2
exit
;;
esac
done
((++OPTIND))
done
}
function consolide_option
{
[ -z "${g_data_file}" ] && { g_data_file=$(mktemp); g_enable_producer='true'; }
g_period=${g_period:-1}
g_column_container=("${g_column_container[@]:-4}")
g_title_container=("${g_title_container[@]:-free}")
g_enable_producer=${g_enable_producer:-false}
g_erase_data=${g_erase_data:-false}
[ "${g_enable_producer}" = 'false' ] && [ ! -f "${g_data_file}" ] && exit
[ ${#g_column_container[@]} = ${#g_title_container[@]} ] || exit
local idx=0
while [ ${idx} -lt ${#g_column_container[@]} ]
do
g_container+=("${g_column_container[idx]}")
g_container+=("${g_title_container[idx]}")
((++idx))
done
}
function data_producer
{
local p_data_output_file=$1
local p_erase_data=$2
if [ "${p_erase_data}" = 'true' ]
then
vmstat -n 1 | sed -u '1,2d' > "${p_data_output_file}"
else
local word_count1=$(tail -2 "${p_data_output_file}" | sed -n '1p' | wc -w)
local word_count2=$(tail -2 "${p_data_output_file}" | sed -n '2p' | wc -w)
if [ ${word_count1} -ne ${word_count2} ]
then
local last_line=$(tail -1 "${p_data_output_file}")
sed -i '$d' "${p_data_output_file}"
echo '# corrupted data: '${last_line} >> "${p_data_output_file}"
fi
echo '# append data begin here' >> "${p_data_output_file}"
vmstat -n 1 | sed -u '1,2d' >> "${p_data_output_file}"
fi
}
function data_extractor
{
local p_data_input_file=$1
local p_data_output_file=$2
sed '$d' "${p_data_input_file}" | grep -v '^#' | nl -v0 > "${p_data_output_file}"
}
function compute_gnuplot_command
{
local p_data_input_file=$1
shift
local p_data_column
local p_data_title
local gnuplot_command
while [ $# -ne 0 ]
do
p_data_column=$1
((++p_data_column))
shift
p_data_title=$1
shift
gnuplot_command+=', '\'${p_data_input_file}\'' using 1:'${p_data_column}' title '\'${p_data_title}\'' with lines'
done
gnuplot_command='plot'${gnuplot_command#,}
echo "${gnuplot_command}"
}
function main
{
local p_data_file=$1
shift
local p_refresh_period=$1
shift
local p_enable_producer=$1
shift
local p_erase_data=$1
shift
trap 'kill -TERM -$$' INT
[ "${p_enable_producer}" = 'true' ] && data_producer "${p_data_file}" "${p_erase_data}" &
local tmp_data_file=$(mktemp)
trap 'rm "'${tmp_data_file}'"' EXIT
local gnuplot_command=$(compute_gnuplot_command "${tmp_data_file}" "$@")
local previous_line_count=0
while true
do
sleep ${p_refresh_period}
local current_line_count=$(wc -l "${p_data_file}" | awk '{print $1}')
if [ ${previous_line_count} -ne ${current_line_count} ]
then
data_extractor "${p_data_file}" "${tmp_data_file}"
echo "${gnuplot_command}"
previous_line_count=${current_line_count}
fi
done
}
parse_option "$@"
consolide_option
main "${g_data_file}" "${g_period}" "${g_enable_producer}" "${g_erase_data}" "${g_container[@]}" | gnuplot -persistent
MORE