7

The following works:

/usr/bin/mysqldump -u[username] -p[password] --all-databases --single-transaction > /home/[domain]/public_html/backups/full_backup_`date -I`.sql

It results in "full_backup_2012-11-04.sql"

The cron job is going every minute but the filename is only for once a day... I wanted to include the hour and minute in the filename as well.... (in the end the cron job might be run every hour or so)

So date -I works... other typical options for date don't seem to work... is there any documentation that says -I is valid? If so that documentation might also have other options that work.

imwill
  • 598
  • 9
  • 25
Luke Wenke
  • 1,149
  • 2
  • 23
  • 43

5 Answers5

3

Use date +%Y-%m-%d_%H-%M-%S instead (or any other format):

EDITED

To avoid long subjects in emails from CRON, use create a file /home/<your user>/mycron.sh (file name and location is just an example):

#!/bin/sh
/usr/bin/mysqldump -u[username] -p[password] --all-databases --single-transaction > /home/[domain]/public_html/backups/full_backup_`date +%Y-%m-%d_%H-%M-%S`.sql

Make sure you chmod +x /home/<your user>/mycron.sh.

This date format will output:

full_backup_2012-11-05_08-49-19.sql

Then use in your cron the name of the script, i.e:

[cron parameters]    /home/<your user>/mycron.sh
JScoobyCed
  • 10,203
  • 6
  • 34
  • 58
  • 1
    Hi I am using cPanel X and I was emailed the following: /bin/sh: -c: line 0: unexpected EOF while looking for matching ``' /bin/sh: -c: line 1: syntax error: unexpected end of file – Luke Wenke Nov 05 '12 at 02:10
  • In my previous post you might want to remove the new lines and the `\\` backslashes. I only placed them here for forum readability. I am editing. – JScoobyCed Nov 05 '12 at 02:49
  • Yep I removed the backslashes. BTW in the subject line of the email it sends me it originally said ".../public_html/backups/full_backup_`date -I`.sql‏" but now it says ".../public_html/backups/full_backup_`date +‏" – Luke Wenke Nov 05 '12 at 03:06
  • See my edit. The subject of the email will not be interpreted. You could use a script to have the subject shorter (only the path of the script) instead of the full command – JScoobyCed Nov 05 '12 at 03:39
  • My point is not that there is a problem with the email subject. The thing is that `date -I` works and every other kind of date format gives errors. (I only get sent an email when there is some kind of error - for -I there usually is no error and it creates the sql file) The date command manual that hd1 mentioned doesn't mention the -I option... I think the solution is one that recognises the -I option but also includes other options. – Luke Wenke Nov 05 '12 at 08:41
  • Ok I see. Yeah the -I option is not in the manual (http://stackoverflow.com/questions/9650041/undocumented-switches-for-date-command). You might want to still use a script and call it by `/foo/bar/mycron.sh \`date -I\`` and ignore the option is the script :D – JScoobyCed Nov 05 '12 at 10:15
2

date -Iminutes could be the way to go, which uses ISO 8601 format. The Wiki page has some info.

Ankur
  • 346
  • 1
  • 3
  • I've got a cron job running twice a day and so far it has added: "full_backup_2012-11-14T00:00-0600.sql" I'll just check that it keeps on working... – Luke Wenke Nov 14 '12 at 08:17
2

While my original script works, something like this may be far simpler:

mysqldump [options] | gzip -c > /backups/data-$(date +%a-%H00).sql.gz

This specifically will keep 7 days worth of backups. It works by using the day of the week plus the hour. So it would look like data-Mon-00.sql.gz (Monday at midnight). When the week rolls around, the previous backups get overwritten.

If you set your cron to run every 6 hours you will get up to 28 backups (24/6) * 7 = 28.

To get a consistent backup with mysqldump you have to lock the tables, so this should only be done from a replica, or a low-volume server. mysqldump also makes a full snapshot, so you end up having a full snapshot for each backup, which can end up taking up a lot of disk space. This can quickly become unmanageable with a large database. You also may not want to trust a replica to take backups from as the replica also has to stay in sync.

A better option is xtrabackup by Percona. It's open source, so it's free. It requires InnoDB tables and is able to take a hot backup of your primary MySQL server without downtime or locks (you shouldn't be using MyISAM anyway). It uses a modified InnoDB engine with InnoDB's crash recovery feature to ensure the backups are consistent. It even takes incremental backups of a base snapshot, so you can make hundreds of backups and have it take up the size of a single snapshot. It works with MySQL, MariaDB, PerconaDB (forks of MySQL), and both InnoDB and XtraDB (improved InnoDB in both in MariaDB and Percona).

Personally I would stick with xtrabackup and not even bother with mysqldump. You have to do just as much work command-line wise, and you have the added benefit of small incremental backups. There are tools out there that automate the use of xtrabackup, even in a Galera cluster. Facebook uses it.


Original script:

The script below takes "backup.sql.gz", for example, and turns it into something like backup-13Nov2012-01_30.sql.gz, then rotates files using hard links.

#!/bin/bash
###########################################################################
# snapshot
#
#     Rotates snapshots of backups using hard links
#
#     Keeps track of:
#          - 48 hours of snapshots (48*60/interval)
#          - 60 days worth of midnight snapshots
#          - 24 months of snapshots from the 1st
#     Ussage:
#          snapshot /path/to/backup.sql.gz
#          mysqldump ... | gzip -c | snapshot /path/to/backup.sql.gz
#
###########################################################################

if ! hash date 2> /dev/null; then
        echo "-snapshot: date command not found" 1>&2
        exit 1
fi

if ! hash ln 2> /dev/null; then
        echo "-snapshot: ln: command not found" 1>&2
        exit 1
fi

# Date Info

month=$(date +"%b")
day=$(date +"%d")
year=$(date +"%Y")
time=$(date +"%H_%M")
date=$(date +"%d%b%Y")
dateFirst=$(date --date="$month 01" +"%d%b%Y" 2> /dev/null)

# Test to see if we're using GNU date or BSD date

if [ "$dateFirst" == "" ]; then
        dateFirst=$(date -v1d +"%d%b%Y")
        back2date=$(date -v-2d +"%d%b%Y")
        back2monthY=$(date -v-2m +"%b%Y")
        back2year=$(date -v-2y +"%Y")
else
        back2date=$(date --date="-2 day" +"%d%b%Y")
        back2monthY=$(date --date="-2 month" +"%b%Y")
        back2year=$(date --date="-2 year" +"%Y")
fi

if [ "$dateFirst" == "" ]; then
        echo "-snapshot: Unknown version of date command." 1>&2
        exit 1
fi

# Directories

filepath=$1
backup=$2

if [ "$filepath" == "" ]; then
        echo "-snapshot: Expecting filename as first argument" 1>&2
        exit 1
fi

if [ "$backup" == "" ]; then
        backup=/backup
fi

if [ ! -d "$backup" ]; then
        echo "-snapshot: Directory "$backup" doesn't exist" 1>&2
        exit 1
fi

snapshots=$backup/snapshots
daily=$backup/daily
monthly=$backup/monthly
basename=${filepath##*/}
ext=${basename#*.}
basename=${basename%%.*}
filename=$basename-$date-$time.$ext

##############################
# Make new snapshot
##############################

if [ ! -d "$snapshots/$date" ]; then
        mkdir -p "$snapshots/$date"
fi

if [ -t 0 ]; then
        if [ ! -f "$filepath" ]; then
                echo "-snapshot: '$filepath' doesn't exist" 1>&2
                exit 1
        fi

    ln "$filepath" "$snapshots/$date/$filename"
else
    cat > "$snapshots/$date/$filename"
fi

##############################
# Daily/monthly snapshots
##############################

if [ "$time" == "00_00" ]; then
        if [ ! -d "$daily/$month$year" ]; then
                mkdir -p "$daily/$month$year"
        fi

        ln "$snapshots/$date/$filename" "$daily/$month$year/$filename"

        if [ "$day" == "01" ]; then
                if [ ! -d "$monthly/$year" ]; then
                        mkdir -p "$monthly/$year"
                fi

                ln "$snapshots/$date/$filename" "$monthly/$year/$filename"
        fi
fi

##############################
# Clean up old snapshots
##############################

if [ -d "$snapshots/$back2date" ]; then
        rm -fr "$snapshots/$back2date"
fi

if [ -d "$daily/$back2monthY" ]; then
        rm -fr "$daily/$back2monthY"
fi

if [ -d "$monthly/$back2year" ]; then
        rm -fr "$monthly/$back2year"
fi
Luke
  • 13,678
  • 7
  • 45
  • 79
2

If you want to do it all in the crontab entry (and not a shell script), here's how:

/usr/bin/mysqldump -u[username] -p[password] --all-databases --single-transaction > /home/[domain]/public_html/backups/full_backup_`date +\%F_\%R`.sql

The filename will output as: full_backup_2017-08-18_17:52.sql

The key change from your command is this: date +\%F_\%R

Note: The % in the date command must be escaped in crontab, otherwise you'll likely get an EOF error. It will work on the command line without escaping the % but won't in crontab. Hope this helps.

Greg Flint
  • 21
  • 1
1

The date(1) command has a "+[FORMAT]" option. I believe the option you want are either the '%s' or '%N' options, which will give you seconds or nanoseconds respectively. From your path for MySQL, I'm going to assume you're on Linux. If this is indeed the case, you can find the manpage here which will give you further details.

hd1
  • 33,938
  • 5
  • 80
  • 91
  • I'm using cPanel X.... BTW the current date option is -I... I can't seem to see that option on that manpage. – Luke Wenke Nov 05 '12 at 02:22