Scripts & schedules
restic can be used as a CLI utility that you run manually when you want to create backups, but you can also script its usage, making it great for scheduled backups. The documentation in this section is not complete, but the Restic docs have an entry for scripting restic that is worth reading.
The documentation on this page assumes you are using my Restic setup docs. If not, you should be able to adapt the scripts for your own setup.
Warning
This documentation is not complete. I am starting by providing example scripts, and will fill in details/write more generic scripts over time. This page is incomplete until this message is gone.
Examples
Generic backup script
If you did not follow my Restic setup guide, or you want to create a more ‘self contained’ script that does not rely on it, you can use something like the script below.
#!/bin/bash
##
# This script is a generic Restic backup script.
# You can use it as a starting/reference point for
# customized backup scripts, or just use this to
# run/schedule backups.
#
# This script assumes you're storing your password
# locally in a file, and using a local repository.
##
## Set default vars
SRC_DIR=""
RESTIC_REPO_FILE=""
RESTIC_PW_FILE=""
DRY_RUN=""
RESTIC_FORCE=""
## Create array of exclude files to pass to restic
EXCLUDE_FILES=()
## Create array of exclude patternss to pass to restic
EXCLUDE_PATTERNS=()
## Define cleanup parameters
DO_CLEANUP=""
KEEP_DAILY=7
KEEP_WEEKLY=4
KEEP_MONTHLY=12
## Define -h/--help function
function print_help() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Restic backup script with support for multiple exclude files and patterns.
OPTIONS:
-s, --backup-src DIR Source directory to back up (required)
-r, --repo-file PATH Path to file with restic repository path (required)
-p, --password-file PATH Path to restic password file (required)
--exclude-file PATH Path to a file containing exclude patterns (can be used multiple times)
--exclude-pattern PATTERN Single exclude pattern (can be used multiple times)
--keep-daily N Retain last N daily snapshots when running with --cleanup (default: $KEEP_DAILY)
--keep-weekly N Retain last N weekly snapshots when running with --cleanup (default: $KEEP_WEEKLY)
--keep-monthly N Retain last N monthly snapshots when running with --cleanup (default: $KEEP_MONTHLY)
-c, --cleanup Run restic cleanup after backup (default: false)
--force Add the --force flag to Restic commands.
--dry-run Print the restic command that would be run, but do not execute
-h, --help Display this help and exit
EXAMPLES:
$(basename "$0") -s /home/username -r /etc/restic/repo -p /etc/restic/pw \
--exclude-file ~/.restic/ignores/default --exclude-pattern "*.cache" --dry-run
NOTES:
- You can specify --exclude-file and --exclude-pattern multiple times to pass multiple values.
- Run with --dry-run to see command without running it.
EOF
}
## Parse CLI args
while [[ $# -gt 0 ]]; do
case "$1" in
-s|--backup-src)
if [[ -z $2 ]]; then
echo "[ERROR] --backup-src provided but no path given."
print_help
exit 1
fi
SRC_DIR="$2"
shift 2
;;
-r|--repo-file)
if [[ -z $2 ]]; then
echo "[ERROR] --repo-file provided but no path given."
print_help
exit 1
fi
RESTIC_REPO_FILE="$2"
shift 2
;;
-p|--password-file)
if [[ -z $2 ]]; then
echo "[ERROR] --password-file provided but no path given."
print_help
exit 1
fi
RESTIC_PW_FILE="$2"
shift 2
;;
--exclude-file)
if [[ -n "$2" && "$2" != --* ]]; then
EXCLUDE_FILES+=("$2")
shift 2
else
echo "[ERROR] --exclude-file provided but no path given."
print_help
exit 1
fi
;;
--exclude-pattern)
if [[ -n "$2" && "$2" != --* ]]; then
EXCLUDE_PATTERNS+=("$2")
shift 2
else
echo "[ERROR] --exclude-pattern provided but no path given."
print_help
exit 1
fi
;;
--keep-daily)
if [[ -n "$2" && "$2" != --* ]]; then
KEEP_DAILY="$2"
shift 2
else
echo "[ERROR] --keep-daily provided but no number given."
print_help
exit 1
fi
;;
--keep-weekly)
if [[ -n "$2" && "$2" != --* ]]; then
KEEP_WEEKLY="$2"
shift 2
else
echo "[ERROR] --keep-weekly provided but no number given."
print_help
exit 1
fi
;;
--keep-monthly)
if [[ -n "$2" && "$2" != --* ]]; then
KEEP_MONTHLY="$2"
shift 2
else
echo "[ERROR] --keep-monthly provided but no number given."
print_help
exit 1
fi
;;
-c|--cleanup)
DO_CLEANUP="true"
shift
;;
-F|--force)
RESTIC_FORCE="true"
shift
;;
--dry-run)
DRY_RUN="true"
shift
;;
-h|--help)
print_help
exit 0
;;
*)
echo "[ERROR] Unrecognized flag: $1"
print_help
exit 1
;;
esac
done
## Export env vars for script
export RESTIC_REPOSITORY_FILE="$RESTIC_REPO_FILE"
export RESTIC_PASSWORD_FILE="$RESTIC_PW_FILE"
if [[ "$SRC_DIR" == "" ]]; then
echo "[ERROR] --source-dir should not be empty"
exit
fi
## Build command
cmd=(restic backup "$SRC_DIR")
## Append all exclude files
for excl_file in "${EXCLUDE_FILES[@]}"; do
cmd+=(--exclude-file "$excl_file")
done
## Append all exclude patterns
for excl_pattern in "${EXCLUDE_PATTERNS[@]}"; do
cmd+=(--exclude "$excl_pattern")
done
## Append --force if RESTIC_FORCE is true
if [[ "$RESTIC_FORCE" != "" ]]; then
cmd+=(--force)
fi
## Print or run command
if [[ -z "$DRY_RUN" ]] || [[ "$DRY_RUN" == "" ]]; then
echo "Running restic backup command: "
echo " $> ${cmd[@]}"
## Run the command
"${cmd[@]}"
if [[ $? -ne 0 ]]; then
echo "[ERROR] Failed to run restic backup command."
if [[ "$DO_CLEANUP" == "true" ]]; then
echo "[WARNING] --cleanup detected, but restic backup failed. Cleanup operation will not run."
fi
exit 1
else
echo "Restic backup performed successfully"
if [[ "$DO_CLEANUP" == "true" ]]; then
cleanup_cmd=(restic forget
--keep-daily "$KEEP_DAILY"
--keep-weekly "$KEEP_WEEKLY"
--keep-monthly "$KEEP_MONTHLY"
--prune
)
echo "Running restic cleanup command: "
echo " $> ${cleanup_cmd[@]}"
"${cleanup_cmd[@]}"
if [[ $? -ne 0 ]]; then
echo "[ERROR] Failed to run restic cleanup command."
fi
fi
exit 0
fi
else
echo "[DRY RUN] Would run restic backup command: "
echo " $> ${cmd[@]}"
exit 0
fiBackup Home
#!/bin/bash
DOT_RESTIC="$HOME/.restic"
DOT_RESTICRC="$DOT_RESTIC/.resticrc"
RESTIC_IGNORES_DIR="$DOT_RESTIC/ignores"
RESTIC_PASSWORDS_DIR="$DOT_RESTIC/passwords"
if [[ ! -d "${DOT_RESTIC}" ]]; then
echo "[ERROR] Could not find restic directory at '${DOT_RESTIC}'"
exit 1
fi
if [[ ! -d "${RESTIC_IGNORES_DIR}" ]]; then
echo "[ERROR] Could not find restic exclude files directory at path '${RESTIC_IGNORES_DIR}'"
exit 1
fi
if [[ ! -d "${RESTIC_PASSWORDS_DIR}" ]]; then
echo "[ERROR] Could not find restic password files directory at path '${RESTIC_PASSWORDS_DIR}'"
exit 1
fi
## Source ~/.restic/.resticrc
if [[ ! -f "${DOT_RESTICRC}" ]]; then
echo "[ERROR] Could not find ~/.restic/.resticrc"
exit 1
fi
. "${DOT_RESTICRC}"
## Ensure ~/.restic/.resticrc values loaded correctly
if [[ -z "${RESTIC_REPOSITORY_FILE}" ]] || [[ "${RESTIC_REPOSITORY_FILE}" == "" ]]; then
echo "[ERROR] RESTIC_REPOSITORY_FILE should not be empty. Ensure ~/.restic/.resticrc defines this variable"
exit 1
fi
if [[ -z "${RESTIC_PASSWORD_FILE}" ]] || [[ "${RESTIC_PASSWORD_FILE}" == "" ]]; then
echo "[ERROR] RESTIC_PASSWORD_FILE should not be empty. Ensure ~/.restic/.resticrc defines this variable"
exit 1
fi
## Ensure restic files exist
if [[ ! -f "${RESTIC_REPOSITORY_FILE}" ]]; then
echo "[ERROR] Could not find Restic repository file at path '$RESTIC_REPOSITORY_FILE'"
exit 1
fi
if [[ ! -f "${RESTIC_PASSWORD_FILE}" ]]; then
echo "[ERROR] Could not find Restic password file at path '$RESTIC_PASSWORD_FILE'"
exit 1
fi
## Set default vars
DRY_RUN=""
## Parse script inputs
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run)
DRY_RUN="true"
shift 1
;;
*)
echo "[ERROR] Unknown argument: $1"
shift 1
;;
esac
done
## Build restic command
cmd="restic backup /home/username --exclude-file \"${RESTIC_IGNORES_DIR}/default\""
## Run or print command
if [[ -z "$DRY_RUN" ]] || [[ "$DRY_RUN" == "" ]]; then
echo "Running restic backup command: $cmd"
eval "${cmd}"
if [[ $? -ne 0 ]]; then
echo "[ERROR] Failed to create restic backup."
exit 1
else
echo "Created restic snapshot of /home/jack"
exit 0
fi
else
echo "[DRY RUN] Would run restic backup command: $cmd"
exit 0
fi