I've working on this script for quite some time. But I started to see some errors when I tried to add a variable ($EMAIL_MSG) to store some strings of text to later be emailed. It seems that the variable inside while loop is not remembered. (A variable modified inside a while loop is not remembered)
Here is part of the script:
#!/bin/bash
#
# This is bash script checks when auto_increment column is reaching its limit
# To run Script $ ./auto_increment_check.sh [username] [password]
MYSQL_USER="$1"
MYSQL_PASSWD="$2"
MYSQLCONNECT="mysql -u$MYSQL_USER -p$MYSQL_PASSWD"
MAX_RATIO="0.8" # Max percentage of fullness of an auto_increment column (ex. '0.8' means 80% full)
EMAIL_MSG=""
EMAIL_RCPNT="user@company.com"
QUERY="
SELECT table_schema,
table_name,
data_type,
( CASE data_type
WHEN 'tinyint' THEN 255
WHEN 'smallint' THEN 65535
WHEN 'mediumint' THEN 16777215
WHEN 'int' THEN 4294967295
WHEN 'bigint' THEN 18446744073709551615
end >> IF(Locate('unsigned', column_type) > 0, 0, 1) ) AS max_value
FROM information_schema.columns
WHERE table_schema NOT IN ( 'mysql', 'information_schema', 'performance_schema')
AND data_type IN ('tinyint','smallint','mediumint','int','bigint')
AND extra = 'auto_increment'"
$MYSQLCONNECT --batch -N -e "$QUERY" | while read DATABASE TABLE DATA_TYPE MAX_VALUE;
do
NEXT_AUTO_INCREMENT=`$MYSQLCONNECT --batch -N -e "show create table $DATABASE.$TABLE" | awk -F'AUTO_INCREMENT=' 'NF==1{print "0";next}{sub(/ .*/,"",$2);print $2}'`
AUTO_INCREMENT_RATIO=$(awk 'BEGIN {printf "%3.2f\n", '$NEXT_AUTO_INCREMENT' / '$MAX_VALUE'}')
if [[ $(awk 'BEGIN{print ('$AUTO_INCREMENT_RATIO'>='$MAX_RATIO')}') -eq 1 ]] ; then
EMAIL_MSG="$EMAIL_MSG\n\nAuto Increment Warning on $(hostname) - $DATABASE.$TABLE - NEXT AUTO INCREMENT: $NEXT_AUTO_INCREMENT, MAX CAPACITY: $MAX_VALUE, RATIO: $AUTO_INCREMENT_RATIO."
fi
done
if [ EMAIL_MSG != "" ]; then
echo -e $EMAIL_MSG | mail -s "Auto Increment Warning on $(hostname) " $EMAIL_RCPNT
fi
The problem seems to be that the while loop is executed in a subshell. So any changes I do for the variable $EMAIL_MSG will not be available once the subshell exits.
I read that I should modify the while loop like this:
while read DATABASE TABLE DATA_TYPE MAX_VALUE;
do
...
...
...
done <<< '$MYSQLCONNECT --batch -N -e "$QUERY"'
if [ EMAIL_MSG != "" ]; then
echo -e $EMAIL_MSG | mail -s "Auto Increment Warning on $(hostname) " $EMAIL_RCPNT
fi
But I'm getting errors:
[root@localhost /]# ./vagrant/auto.sh root root
Mon Jan 27 21:04:01 UTC 2014: Auto Increment Check starting.
./vagrant/auto.sh: line 53: syntax error near unexpected token `--batch'
./vagrant/auto.sh: line 53: `done <<< $MYSQLCONNECT --batch -N -e "$QUERY"'
Any ideas how to fix that?
The following won't do what you think:
because it doesn't expand the variable $EMAIL_MSG, it just uses the literal string "EMAIL_MSG".
Use this:
There are other problems I can see in your script.
The issue of using
<<<
is immaterial. Go back to running a command and piping in towhile
like your original script.Don't use single-quotes if you want to expand shell variables inside the string.
Your passwords will fail if they contain spaces, or semicolon, or ampersand, or hash, or several other special characters.
Actually, I wouldn't use the
-u
and-p
options at all. Put the username and password into a config file and then pass--defaults-extra-file
to load that config file. See http://dev.mysql.com/doc/refman/5.6/en/option-files.htmlThere might be more problems -- that's just what I noticed.
Try:
The construct
<(...)
is called process substitution. It runs the command inside parentheses and makes it output available as if a FIFO had been created. The construct< <(...)
connects the output of the FIFO to stdin on your while loop.Process substitution requires both
bash
and an operating system, such as linux, that supports FIFOs. A mere bourne shell will not support it.Alternatively, this could be done as a here string:
This uses command substitution (
$(...)
) to capture the output of the$MYSQLCONNECT
command and then uses a here-string (<<<
) to provide that as stdin to yourwhile read
loop. Note the double-quotes outside the command substitution. They are necessary to preserve the newlines within the command output. Without those double-quotes, the output of$MYSQLCONNECT
would appear to thewhile read
loop as a single long line.If single-quotes were used instead of double quotes, as in:
then no command would be executed and the literal string
$($MYSQLCONNECT --batch -N -e "$QUERY")
would be provided to thewhile read
loop.