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$USERNAME
you're expecting, and what is the$USERNAME
you're getting instead? Have you created a simple test script to test the value of$USERNAME
when you invoke the script viasudo script-name
vs. 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:25USERNAME
is not a "standard" environment variable and is unlikely to be preserved under the default Ubuntu sudoersenv_reset
policy – steeldriver Dec 19 '22 at 19:46sudo script
vssudo -i script
instead ofsudo script
vsscript
? In what case would thesudo -i
be 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.login
scripts sets$USERNAME
(though it's more often$HOME
that catches people invoking scripts via sudo). My emphasis was more on thesomething like
than 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