\$\begingroup\$
\$\endgroup\$
My bash script mounts two VeraCrypt volumes, rsyncs their contents, and dismounts them. The script takes two parameters, the path for both the source and backup veracrypt volumes. I wrote this script so rsync wouldn't have to copy an entire volume if there was a single change in it.
This is my second time with bash scripting so please let me know what I could do better.
Thanks
#!/bin/bash
# Requirements:
# - Must have both veracrypt and rsync installed
# - Must be ran on Unix based systems
# - Both volumes must have the same password
function prepare_volumes_for_exit() {
# dismount volumes
veracrypt -d
echo "Volumes dismounted"
# delete mount points
sudo rm -r "$source_mount_point"
sudo rm -r "$backup_mount_point"
echo "Mount points purged"
}
# removes double or single quotes from strings of they exist
function format_string() {
if [ "${1:0:1}" == "'" ] && [ "${1: -1}" == "'" ]; then
echo "${1:1:-1}"
elif [ "${1:0:1}" == '"' ] && [ "${1: -1}" == '"' ]; then
echo "${1:1:-1}"
else
echo "1ドル"
fi
}
# make sure all volumes are removed before starting
veracrypt -d
# check that 2 params are passed
if ! [ $# -eq 2 ]; then
echo "Error: 2 parameters are required [source_volume_path] [backup_volume_path]"
exit 1
fi
echo "Enter the password for the veracrypt volume: "
read -s veracrypt_password
# path to veracrypt volumes
source_volume_path="$(format_string "1ドル")"
backup_volume_path="$(format_string "2ドル")"
# generate random mount point
source_mount_point="$(format_string "/mnt/$(uuidgen)")"
backup_mount_point="$(format_string "/mnt/$(uuidgen)")"
# flag to determine if drives are mounted
source_volume_mounted=0
backup_volume_mounted=0
# create mount points
sudo mkdir -p "$source_mount_point"
sudo mkdir -p "$backup_mount_point"
echo "Beginning to mount volumes"
sudo veracrypt -t --mount "$source_volume_path" "$source_mount_point" -p "$veracrypt_password" --non-interactive
# checks that the source volume mounted
while read -r drive_number volume_location vc_mapper mount_location; do
formatted_volume_location="$(format_string "$volume_location")"
formatted_mount_location="$(format_string "$mount_location")"
if [ "$formatted_volume_location" == "$source_volume_path" ] && [ "$formatted_mount_location" == "$source_mount_point" ]; then
echo "Source volume mounted"
source_volume_mounted=1
else
echo "Error: source volume not mounted"
prepare_volumes_for_exit
exit 1
fi
done <<< $(veracrypt -t -l)
sudo veracrypt -t --mount "$backup_volume_path" "$backup_mount_point" -p "$veracrypt_password" --non-interactive
# checks both the source and backup volumes are mounted
# http://mywiki.wooledge.org/BashFAQ/001#source
while read -r drive_number volume_location vc_mapper mount_location; do
formatted_volume_location="$(format_string "$volume_location")"
formatted_mount_location="$(format_string "$mount_location")"
if [ "$formatted_volume_location" == "$source_volume_path" ] && [ "$formatted_mount_location" == "$source_mount_point" ]; then
source_volume_mounted=1
elif [ "$formatted_volume_location" == "$backup_volume_path" ] && [ "$formatted_mount_location" == "$backup_mount_point" ]; then
echo "Backup volume mounted"
backup_volume_mounted=1
else
echo "Error: source or backup volume not mounted"
prepare_volumes_for_exit
exit 1
fi
done <<< $(veracrypt -t -l)
if [ "$source_volume_mounted" -eq 1 ] && [ "$backup_volume_mounted" -eq 1 ]
then
echo "Volumes mounted, beginning rsync"
# sudo rsync -hrtq --exclude-from='/media/miller/Primary/exclude.txt' --delete $source_mount_point/ $backup_mount_point
echo "rsync complete"
else
echo 'Error: Drives were not mounted successfully, skipping rsync'
fi
prepare_volumes_for_exit
echo "Complete"
exit 0
```
1 Answer 1
\$\begingroup\$
\$\endgroup\$
Some suggestions:
#!/usr/bin/env bashis a more portable shebang line.function prepare_volumes_for_exit()can be simplified toprepare_volumes_for_exit().- Using
sudowithin a script is generally discouraged, since it makes it easy to do really bad things without explicit user consent. Instead, remove thesudos and tell the user to run the whole script as root. format_stringis an anti-pattern. First, because quotes are actually valid characters in paths, but more importantly because it is a strong indication that you're expecting the user to wrongly input broken strings.! [ $# -eq 2 ]can be simplified as[ $# -ne 2 ].-
can be improved aswhile read -r drive_number volume_location vc_mapper mount_location ... done <<< $(veracrypt -t -l)
This way, no word splitting happens on the input, and commands within thewhile read -r -u9 drive_number volume_location vc_mapper mount_location ... done 9< <(veracrypt -t -l)whileloop which happen to read from stdin won't break the loop. exit 0is redundant.- By convention, scripts should be silent if there is nothing important to report, and any error messages should go to standard error rather than standard output.
You must log in to answer this question.
lang-bash