Hello all,
i have implemented the functionality to autodetect any ext4 (or any other filesystem spedified) connected disks. You can either still specify an UUID to back up to or let the script select any ext4 disk. It will automatically cycle through the connected disks by saving the last used UUID into the $DATAFILE.
I also moved my script location to a seperate dataset called Scripts as I read that the filesystem of Truenas is not a safe location as it might be deleted on an update.
I might have overengineered the saving functionality of the last UUID but had fun while doing it and either on future amendments it might be useful or other scripts I will work on in the future.
Thanks again for your previous inputs and scripts to copy. @Arwen I copied your script documentation format ![]()
I might still implement the error codes or any bugfixes. For now this is already more then sufficient for me ![]()
Feel free to use any parts of the script for yourself!
I will also edit the first post, once I have the rights to do so. Could anyone help me with this please?
#!/bin/bash
#ident "TrueNAS backup to USB disks 0.02 2025/08/03 Matthias Geffert"
#
# Script name:
# rsync_backup.sh
#
# Description:
# Perform the following:
# - Create a log file
# - Either backups to a specified UUID given as a parameter ./rsync_backup.sh
# e.g. ./rsync_backup.sh e9624b97-f9f1-4048-af11-a91b7dc85d0c
# Or backups to any connected disk with the defined filesystem in configuration
# section and changes the disk each time the script runs
#
# Usage:
# e.g. ./rsync_backup.sh
# e.g. ./rsync_backup.sh e9624b97-f9f1-4048-af11-a91b7dc85d0c
#
# Author info:
# Matthias Geffert
# (C) Copyright Matthias Geffert
#
# Permission and fees:
# You have the right to run this script without any warranty. If you
# find it useful, let me know. If it breaks something, I am not
# responsible. If you modify this script, do not alter my credits,
# add your own.
#
# Notes:
# It is assumed that the backup will fit on the destination. Thus,
# checking log file after backup is helpful to detect errors.
#
# History:
# 2025/07/31 - Matthias Geffert - First version of script
# 2025/08/04 - Matthias Geffert - Added automatic UUID selction and
# read/write functionality to save last used UUID
#
# To be added:
# - creation of exit codes
#
##############################################################################
# debug information for UUID selection
#exec 3>&1 1>"/mnt/Data/Scripts/test.log" 2>&1
##############
#Configuration
##############
DATAFILE="/mnt/Data/Scripts/rsync_backup_data.txt"
LOGFOLDER="/mnt/Data/Dokumente/backup_logs"
SOURCEFOLDERS=("/mnt/Data/Dokumente" "/mnt/Data/Bilder" "/mnt/Data/Backup" "/mnt/Data/Syncthing" "mnt/Data/Scripts")
DESTFOLDER="/mnt/backupdisk"
FILESYSTEMTYPE="ext4"
##############
#Functions
##############
#check if UUID disk is mounted
isUuidMounted() { findmnt --source UUID="$CURUUID" >/dev/null;} #UUID only
#Read data from $DATAFILE
readData() {
SEARCHCONTENT=$1
if test -f $DATAFILE; then
#Read file content into arrays
mapfile -t FILECONTENTNAMES < <( cat $DATAFILE | cut -d'=' -f1)
mapfile -t FILECONTENTVALUES < <( cat $DATAFILE | cut -d'=' -f2)
#Search for Parameter
COUNTCONTENT=${#FILECONTENTNAMES[@]}
for (( i=0; i<$COUNTCONTENT; i++ ));
do
if [ "${FILECONTENTNAMES[$i]}" = "$SEARCHCONTENT" ]; then
#Return Parameter value
echo ${FILECONTENTVALUES[$i]}
fi
done
else
echo "File not found"
fi
}
#Save data to $DATAFILE
saveData() {
PARAMETER=$1
PARAMETERCONTENT=$2
if test -f $DATAFILE; then
#Read file content into arrays
mapfile -t FILECONTENTNAMES < <( cat $DATAFILE | cut -d'=' -f1)
mapfile -t FILECONTENTVALUES < <( cat $DATAFILE | cut -d'=' -f2)
#Search for parameter to write
COUNTCONTENT=${#FILECONTENTNAMES[@]}
for (( i=0; i<$COUNTCONTENT; i++ ));
do
if [ "${FILECONTENTNAMES[$i]}" = "$PARAMETER" ]; then
FILECONTENTVALUES[$i]=$PARAMETERCONTENT
FOUNDPARAMETER=1
fi
done
#write parameter
COUNTCONTENT=${#FILECONTENTNAMES[@]}
WRITEARRAY=
for (( i=0; i<$COUNTCONTENT; i++ ));
do
WRITEARRAY+=${FILECONTENTNAMES[$i]}"="${FILECONTENTVALUES[$i]}"\n"
done
#if parameter has not been found
if [[ ! $FOUNDPARAMETER ]]; then
WRITEARRAY+=$PARAMETER"="$PARAMETERCONTENT"\n"
fi
#if file has not been found
else
WRITEARRAY+=$PARAMETER"="$PARAMETERCONTENT"\n"
fi
printf ${WRITEARRAY[@]} > $DATAFILE
}
######################
#Start of backupscript
######################
#Check if UUID has been given as parameter, otherwise select one of all connected ext4 disks
if [ "$1" != "" ]; then
CURUUID="$1"
else
mapfile -t ALLUUIDS < <( sudo blkid -tTYPE=$FILESYSTEMTYPE -sUUID | cut -d'"' -f2)
#mapfile -t ALLUUIDS < <( sudo blkid -tTYPE=ext4 -sUUID | cut -d'"' -f2)
CURUUID=""
#check if there was saved a previously backup UUID
if test -f $DATAFILE; then
LASTUUID=$(readData "lastUUID")
echo "LASTUUID:"$LASTUUID
if [ ! $LASTUUID = "" ]; then
#loop through UUIDs to check what is the next UUID
COUNTUUIDS=${#ALLUUIDS[@]}
for (( i=0; i<COUNTUUIDS; i++ ));
do
if [ "${ALLUUIDS[$i]}" = "$LASTUUID" ]; then
CURUUID=${ALLUUIDS[$i + 1]}
fi
done
#if the File for storage of UUID has not been found or UUID was at the end of array use the first UUID
if [ "$CURUUID" = "File not found" ] || [ "$CURUUID" = "" ]; then
CURUUID=${ALLUUIDS[0]}
fi
#if LASTUUID is empty
else
CURUUID=${ALLUUIDS[0]}
fi
#if $DATAFILE does not exist
else
CURUUID=${ALLUUIDS[0]}
fi
#save current used UUID
saveData "lastUUID" $CURUUID
fi
#debug info for UUID selection
echo "array0 :"${ALLUUIDS[0]}
echo "array1 :"${ALLUUIDS[1]}
echo "array2 :"${ALLUUIDS[2]}
echo "array3 :"${ALLUUIDS[3]}
echo "LASTUUID:"$LASTUUID
echo "CURUUID :"$CURUUID
#set Logfilename
LOGDATE=$(date +"%Y%m%d-%H%M%S")
LOGNAME=$LOGDATE"_"$CURUUID
#mount UUID Disk
mkdir -p /mnt/backupdisk
mount UUID=$CURUUID /mnt/backupdisk
#create logfile
mkdir -p $LOGFOLDER
LOGFILE=$LOGFOLDER"/"$LOGNAME".log"
exec 3>&1 1>"$LOGFILE" 2>&1
#Start backup
echo "Start: "$(date -R)
echo "UUID: "$CURUUID
echo "#############################################################"
echo
#check if disk is mounted
if isUuidMounted $CURUUID;
then
echo "Disk is mounted"
echo
echo "#############################################################"
echo "Truenas Configuration Backup"
echo "#############################################################"
echo
mkdir -p $DESTFOLDER"/truenas_config"
rsync -rltgoDv /var/db/system/configs-*/ $DESTFOLDER"/truenas_config"
#do backup of all specified folders
for FOLDER in "${SOURCEFOLDERS[@]}"
do
echo
echo "#############################################################"
echo "Sourcefolder: " $FOLDER
echo "#############################################################"
echo
mkdir -p $FOLDER
rsync -rltgoDv $FOLDER $DESTFOLDER
done
else
echo "Disk is not mounted"
fi
#unmount disk
umount /mnt/backupdisk
echo
echo "#############################################################"
echo "End: "$(date -R)
echo "#############################################################"
exit 0