2
\$\begingroup\$

I have written this shell script to backup MySQL database to disk. It works fine but I am not well proficient in shell scripting. So what do you think can it be improved?

#!/bin/bash
#For taking backup
APPEND_CLI=3ドル
DIR=/media/storage/backup/db_backup/
DATESTAMP=$(date +%d-%m-%y-%H-%M)
DB_USER=backup
DB_PORT=2ドル
DB_PASS='readonly'
HOST=1ドル
if [[ `id -u` != 0 ]]; then
 echo "Must be root to run script"
 exit
fi
if test -z "$HOST"
then
 echo "HOST not passed."
 exit 1
fi
if test -z "$DB_PORT"
then
 echo "PORT not passed."
 exit 1
fi
# remove backups older than $DAYS_KEEP
DAYS_KEEP=7
find ${DIR}* -mtime +$DAYS_KEEP -exec rm -f {} \; 2> /dev/null
# create backups securely
umask 006
# list MySQL databases and dump each
DB_LIST=`$APPEND_CLI mysql -h $HOST -u $DB_USER -p"$DB_PASS" -e'show databases;'`
echo "Listing databases"
echo ${DB_LIST##Database}
DB_LIST=${DB_LIST##Database}
for DB in $DB_LIST;
do
 if [[ "${DB}" == "performance_schema" ]]
 then
 echo "Skipping database ${DB}."
 continue
 fi
 FILENAME=${DIR}${DB}-${DATESTAMP}.msql.${DB_PORT}.gz
 echo "Initiating backup of $DB for ${HOST} on port ${DB_PORT}"
 $APPEND_CLI mysqldump -h $HOST -P $DB_PORT -u $DB_USER -p"$DB_PASS" $DB --single-transaction | gzip > $FILENAME
 echo "Done backing up ${FILENAME}"
done
asked Feb 18, 2022 at 19:11
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Please use lower-case for Bash variables - upper-case is normally used for environment variables that communicate with child processes.


if [[ `id -u` != 0 ]]; then
 echo "Must be root to run script"
 exit
fi

Error messages should go to the standard error stream (>&2). And I think we should be exiting with a failure status in this case (since we didn't perform the requested backup).

We can make life easier for ourselves with a short function to print an error message and exit with failure. That looks like

die() {
 echo >&2 "$@"
 exit 1
}

Then our three tests become simpler:

[ "$(id -u)" = 0 ] || die "Must be root to run script"
[ -n "$HOST" ] || die "HOST not passed."
[ -n "$DB_PORT" ] || die "PORT not passed."

Instead of the continue to skip over the performance_schema database, we could exclude it from our results:

mysql -e 'show databases where `Database` not like "performance_schema"'

And we can avoid the need to remove the Database column header by passing --skip-column-names.


Since we're using Bash, which has arrays, we should use an array for the list of databases, particularly in case they might contain spaces in their names.

We can use read -a to assign input lines to an array:

IFS=$'\n' read -d '' -r -a db_list \
 < <(mysql --batch --skip-column-names -e 'show databases')

Then we can loop over the names:

for db in "${db_list[@]}"
do
 filename=${dir}${db}-${datestamp}.msql.${db_port}.gz
 echo "Initiating backup of $db for ${host} on port ${db_port}"
 $append_cli mysqldump \
 -h "$host" -P "$db_port" -u "$db_user" -p"$db_pass" "$db"
 --single-transaction \
 | gzip >$filename
 echo "Done backing up ${filename}"
done
answered Feb 18, 2022 at 21:41
\$\endgroup\$
2
  • \$\begingroup\$ thanks I am wondering how can not delete the old back if its the last and only one in that backup directory. \$\endgroup\$ Commented Feb 18, 2022 at 22:04
  • \$\begingroup\$ You might be better leaving that logic out of your script and using something external (logrotate) to deal with that for you. It's probably easier to configure that than to write and test your own version. I was going to mention that, but got distracted. \$\endgroup\$ Commented Feb 18, 2022 at 22:10

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.