I am writing a script in Bash that should automate the actions necessary to backup my hard drive using the rsync command. In this implementation, I am setting the script up to complete the following steps
- Determine the base directory where the backup will be mounted based on the Linux distobution
- Determine if rsync is installed, and prompt the user to install it if it is not
- Prompt the user to select the correct mounted drive at the base directory
- Create a backup file in the correct directory where the backup directory is given a title in the format
YYYY-MM-DD:H:M:S - Conduct the backup using
rsync - Determine if there are more than 4 backup directories, and if so, delete the oldest
I am posting the while script for completeness; however, the problem I am having is occurring on line 165. The script is stored in my usr/local/bin directory and run either with or without the sudo command. If it is run without the sudo command (i.e. backup), whenever it comes to a location in the script where sudo is invoked, it will prompt the user for his or her password and it runs correctly. However, I would like to run the file with sudo upfront (i.e. sudo backup) so the user does not need to sit by his or her computer waiting for the script to prompt them to enter their password. I would rather they entered their password once, and the whole script ran without the need for more user inputs. Unfortunately when I do this, instead of creating the backup directory in the backup drive (i.e. /run/media/username/YYYY-MM-DD:H:M:S) it creates the directory in the media directory (i.e. /run/media/YYYY-MM-DD:H:M:S). Can anyone tell me why this works when I do not invoke the script with sudo but does not work when I do use sudo?
Fore reference, /usr/local/bin is in my PATH, so I can call the script by backup instead of ./backup or bash backup
#!/usr/bin/bash
# backup file
# ================================================================================
# ================================================================================
# - Purpose: This file contains scripts that will create a user defined number
# of backup snapshots, where each snapshot is a full backup
# of the hard drive
#
# Source Metadata
# - Author: First Name, Last Name
# - Date: December 15, 2022
# - Version: 2.0
# - Copyright: Copyright 2022, XXXX Inc.
# ================================================================================
# ================================================================================
# Set command path lengths
NUM_DIRS=4 # Number of backups allowed on the backup drive
make_dir=/usr/bin/mkdir
remove_dir=/usr/bin/rm
nfind=/usr/bin/find
cdat=/usr/bin/rsync
log_path=~/backup.log
--------------------------------------------------------------------------------
Define base directory for backup drive based on Linux distrobution
cur_dir=pwd
linux_file=/etc/os-release
- This if statement will determine the correct media directory where
the backup drive will be mounted
if grep -q "Arch" $linux_file
then
# The host is an Arch based distribution
media_dir=/run/media/$USERNAME/
elif grep -q "Ubuntu" $linux_file || grep -q "Pop" $linux_file
then
# The host is an Ubuntu or Pop OS based distribution
media_dir=/media/$USERNAME/
else
# The host is not a compatible distribution
echo "Linux distribution not supported, exiting"
exit 1
fi
--------------------------------------------------------------------------------
Ensure that rsync is appropriately installed
if ! command -v rsync > /dev/null 2>&1 && grep -q "Arch" $linux_file
then
echo "rsync is not installed"
echo "Install rsync with the command 'sudo pacman -S rsync'"
exit 3
elif ! command -v rsync > /dev/null 2>&1
then
echo "rsync is not installed"
echo "Install rsync with the command 'sudo apt install rsync'"
exit 3
fi
--------------------------------------------------------------------------------
Determine which drive to pair with the base directory
This command will determine the mounted directories in the media directory
potential_dirs=($(ls -l $media_dir | awk '/^d/ {print $9}'))
Let the user select the correct drive to contain the backup
count=0
echo "Select the number of the appropriate backup directory"
for dir in ${potential_dirs[@]};
do
echo $count")" $dir
let count++
done
echo $count") None"
read option;
Verify the user entered the correct value
if [ $option -eq $count ];
then
echo "User required option not available, exiting!"
exit 0
fi
if [ $option -gt $count ] || [ $option -lt 0 ];
then
echo "User entered and invalid number, exiting!"
exit 2
fi
Verify the correct drive was selected
echo "Are you sure ${potential_dirs[option]} is the correct option (Y/N)"
read assertion
if [ "$answer" != "${answer#[Yy]}" ] ;
then
echo "Exiting!"
return 0
fi
DATE=date +%F:%H:%M:%S
base_dir=$media_dir${potential_dirs[option]}'/'
backup_drive=$media_dir${potential_dirs[option]}'/'$DATE
Create directory
sudo $make_dir $backup_drive
--------------------------------------------------------------------------------
Backup data
sudo $cdat -aAXHv --delete --exclude={"/dev/","/proc/","/sys/","/run/","/mnt/","/media/","lost+found","swapfile"} / $backup_drive
--------------------------------------------------------------------------------
Determine the number of directories in the backup dir and number to be deleted
Count the number of directories in the backup directory
dir_num=$nfind $base_dir -mindepth 1 -maxdepth 1 -type d | wc -l
Determine the number of directories to be deleted
num_delete="$(($dir_num-$NUM_DIRS))"
Change to backup directory
cd $base_dir
Delete the oldest directories if necessary
if [ $num_delete -gt 0 ] ; then
dirs=ls -d */ | cut -f1 -d'/' | head -n $num_delete
for variable in $dirs
do
echo "Removing $variable directory"
sudo rm -r $variable
done
fi
Return to the initial directory
cd pwd
Write succesful results to log file
good_msg=$USERNAME' hard drive succesfully backed up on '$DATE#
/usr/bin/echo $good_msg >> $log_path
================================================================================
================================================================================
exit 0
/media. The script determines this by invoking eithermedia_dir=/media/$USERNAME/ormedia_dir=/run/media/$USERNAME/. What is the$USERNAMEyou're expecting, and what is the$USERNAMEyou're getting instead? Have you created a simple test script to test the value of$USERNAMEwhen you invoke the script viasudo script-namevs. something likesudo -i script-name? Have you looked in the sudo man page or other docs to see what makes sudo change that variable? – Sotto Voce Dec 19 '22 at 19:25USERNAMEis not a "standard" environment variable and is unlikely to be preserved under the default Ubuntu sudoersenv_resetpolicy – steeldriver Dec 19 '22 at 19:46sudo scriptvssudo -i scriptinstead ofsudo scriptvsscript? In what case would thesudo -ibe different? If there were something in root's bashrc or profile that set the variable? Or is there something else? – terdon Dec 19 '22 at 21:10.profile,.bash_profile, or.loginscripts sets$USERNAME(though it's more often$HOMEthat catches people invoking scripts via sudo). My emphasis was more on thesomething likethan onsudo -i. – Sotto Voce Dec 19 '22 at 21:41:) as they may fail on certain filesystems. And even if they don't fail immediately they can be unreadable by certain OSes. – Chris Davies Dec 19 '22 at 21:52