Skip to main content
1 of 4
Riv
  • 195
  • 1
  • 5

Linux backup script written in bash for tar

This is my first attempt at scripting with bash. I am running Ubuntu server, so I don't get to use all the gui back ups out there. Besides, tar works fine for personal use. Please let me know of any improvements and why.

#!/bin/bash

# PURPOSE:
# TO BACK UP ALL FILES AND FOLDERS FROM A GIVEN DIRECTORY
# Directory to back up is set with the constant BACK_UP_LOCATION
# Directory to save the back up to is /IT/backup/ and is set with the constant BACK_UP_DIR
# Directory to save the log files to is /IT/backup/log/ and is set by changing the tail end of the constant BACK_UP_LOG_DIR
# Obviously additional directories can be added to the back up by adding additional constants and incorporating that tar command(s) to go with them

# Written by Rowland Holden

# This script could have used the find command to delete the old files
# but that wouldn't have allowed for the logging of each deleted file so
# I chose to do it the long way to get the logging I wanted

# File Info: tar-share-backup @ cron.daily




# Set constants

NOW=$(date +%m-%d-%Y)
BACK_UP_DIR="IT/backup/"
BACK_UP_PATH="${BACK_UP_DIR}ShareBackup${NOW}"
BACK_UP_LOG_DIR="${BACK_UP_DIR}log/"
BACK_UP_LOG_PATH="${BACK_UP_LOG_DIR}ShareBackupLog${NOW}"
BACK_UP_LOCATION="srv/share/"

cd /

# check if script is already running

write_pid_running_error () {

  local  errorText="${0} is already running: canceling backup operation"

  if [[ -f "${BACK_UP_LOG_PATH}" ]]; then
    echo "" >> "${BACK_UP_LOG_PATH}"
    echo "${errorText}" >> "${BACK_UP_LOG_PATH}"
  else
    echo "${errorText}" > "${BACK_UP_LOG_PATH}"
  fi


}

for pid in $(pidof -x `basename $0`); do
  if [[ $pid != $$ ]]; then
    write_pid_running_error
    exit 1
  fi
done


# Check to see if the back up file already exists and write an error in the log if it does

# write error to log file if back up file exists
write_file_exists_error () {

  local  errorText="backup file already exists: canceling backup operation"

  if [[ -f "${BACK_UP_LOG_PATH}" ]]; then
    echo "" >> "${BACK_UP_LOG_PATH}"
    echo "${errorText}" >> "${BACK_UP_LOG_PATH}"
  else
    echo "${errorText}" > "${BACK_UP_LOG_PATH}"
  fi

}

# check to see if th back up tar file already exists - if so let the user know in the log and exit -
# do not continue because we don't know if the user wants to rm the file or not
check_file () {

  if [[ -f "${BACK_UP_PATH}.tar.gz" ]]; then
    write_file_exists_error
    exit 1
  fi

}

del_files () {

  local filepath="${1}"
  local modDate="${2}"
  local file="${3}"
  local dir="${4}"

  local delCutOffDate=$(date -d "$date -7 days" +%m-%d-%Y) # sets date to 7 days ago

  if [[ -f "${filepath}" ]]; then # make sure $file is an actual file and not a directory
    if [[ "${modDate}" -ot "${delCutOffDate}" ]]; then  # Compares the file modified date to the cut off date for deletion - anything older than 7 days
      echo "  ${file} deleted from ${dir}" >> "${BACK_UP_LOG_PATH}"
      echo "    ModDate: ${modDate}" >> "${BACK_UP_LOG_PATH}"
      echo "    Cut Off: ${delCutOffDate}" >> "${BACK_UP_LOG_PATH}"
      echo "    test: ${modDate} -ot ${delCustOffDate}" >> "${BACK_UP_LOG_PATH}"
      rm "${filepath}" >> "${BACK_UP_LOG_PATH}"
    fi
  fi
}

cycle_files () {

  local files=("$@")
  local dir="${files[-1]}" # $ is set on the number of arguments, so this wouldn't be $1, it would be $ whatever the last index in the argument array is
         # This is because the number of files are dynamic, making the array indexing dynamic. making this way the best to obtain the dir we want

  unset 'files[-1]' # remove the directory as filepath prefixes the file with the directory - prefixing a directory to a directory will throw an error

  for file in "${files[@]}"; do # for each file in the current directory do the following loop
    filepath="${dir}${file}" # prefix the filename with the directory path for file manipulation
    modDate=$(date -r "${filepath}" +%m-%d-%Y) # Gets modified date of a file

    del_files "${filepath}" "${modDate}" "${file}" "${dir}"
  done

}

cycle_dirs () {

  local dirs=("$@")

  for dir in "${dirs[@]}"; do # for each directory do the following loop
    files=($(ls "${dir}")) # list all files in $dir and put them in an array
    echo "Enterying: ${dir}" >> "${BACK_UP_LOG_PATH}"

    cycle_files "${files[@]}" "${dir}"
  done

}

delete_old_files () {

  echo "" >> "${BACK_UP_LOG_PATH}"
  echo "" >> "${BACK_UP_LOG_PATH}"
  echo "The folowing files were deleted:" >> "${BACK_UP_LOG_PATH}"
  echo "" >> "${BACK_UP_LOG_PATH}"

  dirs=( "${BACK_UP_DIR}" "${BACK_UP_LOG_DIR}" ) # create an array of directories to cycle through for deleting old back up and log files
  cycle_dirs  "${dirs[@]}"

}

check_file

# Back up files

echo "The following files were backed up:" > "${BACK_UP_LOG_PATH}" # if we have gotten this far we have a clean back up file so lets also do a clean log
echo "" >> "${BACK_UP_LOG_PATH}"

tar -czvf "${BACK_UP_PATH}.tar.gz" "${BACK_UP_LOCATION}" >> "${BACK_UP_LOG_PATH}"

# Delete old log and back up files
  delete_old_files

exit 0
Riv
  • 195
  • 1
  • 5