while循环中的变量不会被记住。 Mysql bash脚本auto_increment

时间:2014-01-27 23:12:07

标签: mysql bash shell while-loop auto-increment

我已经在这个脚本上工作了很长时间。但是当我尝试添加变量($ EMAIL_MSG)来存储一些文本字符串以便稍后通过电子邮件发送时,我开始看到一些错误。看来while循环中的变量不会被记住。 (A variable modified inside a while loop is not remembered

以下是该脚本的一部分:

#!/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

问题似乎是while循环在子shell中执行。因此,一旦子shell退出,我对变量$ EMAIL_MSG所做的任何更改都将无法使用。

我读到我应该像这样修改while循环:

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

但我收到了错误:

[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"'

任何想法如何解决?

2 个答案:

答案 0 :(得分:2)

尝试:

done < <($MYSQLCONNECT --batch -N -e "$QUERY")

构造<(...)称为进程替换。它在括号内运行命令并使其输出可用,就像创建了FIFO一样。构造< <(...)将FIFO的输出连接到while循环上的stdin。

进程替换需要bash和支持FIFO的操作系统,例如linux。仅仅是bourne shell就不会支持它。

或者,这可以作为一个字符串来完成:

done <<<"$($MYSQLCONNECT --batch -N -e "$QUERY")"

这使用命令替换($(...))来捕获$MYSQLCONNECT命令的输出,然后使用here-string(<<<)将stdin提供给{{1}循环。请注意命令替换之外的双引号。它们是保留命令输出中的换行符所必需的。如果没有这些双引号,while read的输出在$MYSQLCONNECT循环中会显示为一条长行。

如果使用单引号而不是双引号,如:

while read

然后不会执行任何命令,文字字符串done <<<'$($MYSQLCONNECT --batch -N -e "$QUERY")' # Don't use this 将被提供给$($MYSQLCONNECT --batch -N -e "$QUERY")循环。

答案 1 :(得分:0)

以下不会做您的想法:

if [ EMAIL_MSG != "" ]; then

因为它没有扩展变量$ EMAIL_MSG,所以它只使用文字字符串&#34; EMAIL_MSG&#34;。

使用此:

if [ ! -z "$EMAIL_MSG" ]; then

我可以在您的脚本中看到其他问题。

  • 使用<<<的问题并不重要。返回运行命令并像原始脚本一样输入while

  • 如果要在字符串中展开shell变量,请不要使用单引号。

  • 如果密码包含空格,分号或&符号,哈希值或其他几个特殊字符,则密码将失败。

    实际上,我根本不会使用-u-p选项。将用户名和密码放入配置文件,然后传递--defaults-extra-file以加载该配置文件。请参阅http://dev.mysql.com/doc/refman/5.6/en/option-files.html

可能会有更多问题 - 这正是我注意到的。