Search code examples
bashmysqlbzip2

How to determine if a bzipped mysqldump file is empty / zero size?


I want to write a bash function to test whether or not a mysqldump command succeeded. What I've tried so far is to test whether the dump file is zero size or not, like this:

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

I decided to test this way, rather than to test the exit status of the mysqldump command, because when the default mysql server is down, running a mysqldump command gives this error:

mysqldump: Got error: 2002: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) when trying to connect

Even though it throws up this error, it still generates a 0 byte .mssql file. Also, the exit status is 0 no matter what. The script has to exit if the dump failed, and needs to communicate to the user that they need to either specify a different mysqldump binary or to activate their server.

The above piece of code works fine. However, I don't want mysqldump to generate an uncompressed dump file. I want to bzip it, like this:

${l_mysqldump:-mysqldump} -u$l_db_user -p$l_db_pass -h $l_db_host $l_db_name | bzip2 -c > latest-dump.mssql.bz2

The problem is, this breaks my [-s] bash test, because the .bz2 file it generates is 14 bytes. So even though the uncompressed .mssql file is size zero, the equivalent archive is not size zero.

So what's the best way to solve this? I could just generate an uncompressed dump file, test it, then bzip it after. I suspect there is a much smarter way to do this however.


Solution

  • The real problem is that with a pipe, the default return status is the exit code of the last command (bzip2). To quote 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.
    

    If you want to report failure if any command of the pipe failed, you have to set the pipefail option. Assuming bash, here is an example (I don't have mysql server running on localhost):

    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
    

    For your particular case, you will write something like:

    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 command gives this error [..] Even though it throws up this error, it still generates a 0 byte .mssql file."

    To be more precise, since you use shell redirection, it is the host shell that create the file. Before it even tried to run the command.