2

我想编写一个 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: Got error: 2002: Can't connect to local MySQL server through socket '/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 压缩。我怀疑有一种更聪明的方法可以做到这一点。

4

2 回答 2

3

真正的问题是,对于管道,默认返回状态是最后一个命令的退出代码 ( 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


顺便说一句:“ mysqldump命令给出了这个错误 [..] 即使抛出了这个错误,仍然会生成一个 0 字节的 .mssql 文件。”

更准确地说,由于您使用 shell重定向,因此创建文件的是主机 shell。在它甚至尝试运行命令之前。

于 2013-08-12T10:40:47.647 回答
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:”或只是“Got error:”。例如

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
...
于 2013-08-12T10:54:14.560 回答