我已经在这个脚本上工作了很长时间。但是当我尝试添加变量($ 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"'
任何想法如何解决?
答案 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
可能会有更多问题 - 这正是我注意到的。