我想编写一个bash函数来测试mysqldump
命令是否成功。到目前为止我尝试过的是测试转储文件是否为零大小,如下所示:
l_mysqldump= # set your custom mysqldump path here, like /Applications/MAMP/Library/bin/mysqldump
${l_mysqldump:-mysqldump} -u$l_db_user -p$l_db_pass -h $l_db_host $l_db_name > latest-dump.mssql
if [[ -s latest-dump.mssql ]]
then
echo "Success: not zero size."
else
echo "Error: zero size."
exit 1
fi
我决定以这种方式测试,而不是测试mysqldump
命令的退出状态,因为当默认的mysql服务器关闭时,运行mysqldump
命令会出现此错误:
mysqldump:收到错误:2002:无法通过套接字连接到本地MySQL服务器 '/tmp/mysql.sock'(2)尝试连接时
即使它抛出此错误,它仍然会生成一个0字节的.mssql文件。此外,无论如何,退出状态为0。如果转储失败,脚本必须退出,并且需要与用户通信他们需要指定不同的mysqldump
二进制文件或激活其服务器。
上面的代码工作正常。但是,我不希望mysqldump
生成未压缩的转储文件。我想对它进行bzip,就像这样:
${l_mysqldump:-mysqldump} -u$l_db_user -p$l_db_pass -h $l_db_host $l_db_name | bzip2 -c > latest-dump.mssql.bz2
问题是,这会破坏我的[-s]
bash测试,因为它生成的.bz2文件是14个字节。因此,即使未压缩的.mssql文件的大小为零,等效存档也不是零大小。
那么解决这个问题的最佳方法是什么?我可以生成一个未压缩的转储文件,对其进行测试,然后对其进行bzip。 我怀疑有一种更明智的方法可以做到这一点。
答案 0 :(得分:3)
真正的问题是,对于管道,默认返回状态是 last 命令(bzip2
)的退出代码。引用man bash
:
The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit success‐ fully.
如果要在管道的任何命令失败时报告失败,则必须设置pipefail
选项。假设bash
,这是一个例子(我没有在localhost上运行mysql服务器):
sylvain@daal:~$ set -o pipefail
sylvain@daal:~$ if mysqldump -u root -p db | bzip2 -c > latest-dump.mssql.bz2; then echo ok; else echo non ok; fi
Enter password:
mysqldump: Got error: 2002: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2) when trying to connect
non ok
对于您的特定情况,您将编写如下内容:
set -o pipefail
if ${l_mysqldump:-mysqldump} -u$l_db_user -p$l_db_pass -h $l_db_host $l_db_name | bzip2 -c > latest-dump.mssql.bz2
then
...
fi
<小时/> <子> BTW:“ mysqldump 命令发出此错误[..]即使它引发此错误,它仍然会生成一个0字节.mssql文件。“
更准确地说,由于您使用shell 重定向,因此它是创建该文件的主机shell。在它甚至尝试运行命令之前。
子>答案 1 :(得分:1)
如何检查mysql命令中的常见错误字符串?您可以在重定向stdout和stderr:
时将命令放在进程子代码中IFS= read -rd '' OUTPUT < <(${l_mysqldump:-mysqldump} -u$l_db_user -p$l_db_pass -h $l_db_host $l_db_name 2>&1 > >(bzip2 -c > latest-dump.mssql.bz2))
然后用grep,case,[[==]]或[[=〜]]正常检查输出,例如
if echo "$OUTPUT" | grep "error" >/dev/null; then
(failure)
else
(success)
fi
case "$OUTPUT" in
*"error"*|*another_error_pattern*|...)
(failure)
;;
*)
(success)
;;
esac
也许另一种方法是检查输出文件的大小是否大于默认大小14,但我认为不太确定。
${l_mysqldump:-mysqldump} -u$l_db_user -p$l_db_pass -h $l_db_host $l_db_name > latest-dump.mssql
if IFS= read SIZE < <(stat -c "%s" latest-dump.mssql) && [[ SIZE -gt 14 ]]; then
(success)
else
(fail)
fi
正确引用变量以防止意外扩展是一个好主意:
"${l_mysqldump:-mysqldump}" "-u$l_db_user" "-p$l_db_pass" -h "$l_db_host" "$l_db_name" > latest-dump.mssql
更新:看到你的更新,我认为你的错误输出模式的理想字符串将是“mysqldump:Got error:”或只是“得到错误:”。 e.g。
IFS= read -rd '' OUTPUT < <("${l_mysqldump:-mysqldump}" -u"$l_db_user" -p"$l_db_pass" -h "$l_db_host" "$l_db_name" 2>&1 > >(bzip2 -c > latest-dump.mssql.bz2))
if echo "$OUTPUT" | grep "Got error:" >/dev/null; then
...
if grep "Got error:" >/dev/null <<< "$OUTPUT"; then
...
case "$OUTPUT" in
*"Got error:"*)
...
if [[ $OUTPUT == *"Got error:"* ]]; then
...