Self-review for the follow-up question, which I will post in the following days.
Treat unset variables as an error when substituting
Add this to the beginning of the script:
set -o nounset
[ "$#" -eq 0 ]
instead of [ -z "$1" ]
It seems testing number of arguments is a better approach than testing if the first argument is set. Also, I added:
[ "$#" -gt 1 ] && echo "Multiple arguments are not supported!" && exit 1
for an obvious reason.
As pointed out by Janos, put password file path into variable
And put it in the beginning of the script (maybe with a comment).
# In order to compress many directories with the same password,
# I decided to create a password file to avoid too many annoying prompts
passwd_file="/home/vlastimil/.blablablabla"
Test for the existence of the password file
It may happen that you migrate to a different platform and / or accidentally delete the file.
[ ! -f "$passwd_file" ] && echo "The password file does not exist!" && exit 1
You should also test for existence of the processed files
Like this, the comments are optional:
# TAR is archiving the directory into the following temporary file,
# it gets deleted on successful processing
[ -f "${backup_file}" ] && echo "File ${backup_file} exists, exiting." && exit 1
# XZ is compressing the archive into the following temporary file,
# it gets deleted on successful processing
[ -f "${backup_file}.xz" ] && echo "File ${backup_file}.xz exists, exiting." && exit 1
# OpenSSL is decrypting the file (for verification) into the following temporary file,
# it gets deleted on successful processing
[ -f "${backup_file}.xz.dec" ] && echo "File ${backup_file}.xz.dec exists, exiting." && exit 1
# OpenSSL is encrypting the compressed file into the following permanent file,
# this is the result of successful processing
[ -f "${backup_file}.xz.enc" ] && echo "File ${backup_file}.xz.enc exists, exiting." && exit 1
# SHA512SUM is computing a hash sum of the encrypted file into the following permanent file,
# this is the result of successful processing
[ -f "${backup_file}.xz.enc.SHA512SUM" ] && echo "File ${backup_file}.xz.enc.SHA512SUM exists, exiting." && exit 1
Define all common colors (optional)
It happens one might like a change and / or later wants to re-define the styling. So this may be good idea, just comment out the colors that you don't use.
red=$(tput setaf 1)
blue=$(tput setaf 4)
cyan=$(tput setaf 6)
green=$(tput setaf 2)
white=$(tput setaf 7)
yellow=$(tput setaf 3)
magenta=$(tput setaf 5)
As pointed out by Janos, color definitions should be renamed
I would rename bold_red and bold_yellow to be more about the purpose than presentation.
And I agree:
action_number_color="${bold}${red}"
action_color="${bold}${yellow}"
file_color="${bold}${white}"
success_color="${bold}${green}"
Again, as pointed out by Janos, there should be a helper printing function
A helper function would be more convenient to print the headers for the steps, instead of blocks of echo
s.
Like this, I added some leading and trailing coloring:
print_action()
{
echo
echo "${action_number_color}$1${no_color}"
echo
}
There could be a helper error function too
For instance:
print_error()
{
echo
echo "$1"
exit 1
}
There are too long lines of strings
Both in the code, and in the output. It could be simplified for example:
print_action "1/7:${action_color}
TAR is archiving the directory
${file_color}${dir}${action_color}
into
${file_color}${backup_file}"
tar --verify
for enhanced integrity
The man page says:
-W, --verify: attempt to verify the archive after writing it
Just to note: I take it, this option is only usable when creating the archive, and not if later checking the integrity.
if
s can be completely pulled out of the whole script
More importantly, it makes the script more readable this way:
tar --create --file="${backup_file}" "$1" --totals --verify ||
print_error "TAR failed to archive the directory!"
Too long lines of code could be split
There were also places where the code itself could be formatted in two lines simply with the already present |
(pipe), which acts as delimiter too.
pv --progress --timer --eta --rate --average-rate --bytes "${backup_file}.xz" |
openssl enc -aes-256-cbc -md sha256 -salt -out "${backup_file}.xz.enc" -pass file:"$passwd_file" 2> /dev/null ||
print_error "OpenSSL failed to encrypt the compressed file!"
Average rate could further be added to the pv
statement
As shown above, this could be somewhat useful to me at least if the file is very large.
Remove -W
parameter from pv
The --wait
parameter is useless in case like this, where we are not waiting for user input. What's more, it caused pv
not to output anything on small files.
As pointed out by Janos, remove the sha512sum --check
Not only it is useless in this case, but it takes a few seconds. Better yet, you could replace it with showing the SHA-512 hash sum like this:
awk '{ print $1 }' "${backup_file}.xz.enc.SHA512SUM"
Use cmp
with --silent
parameter
As you are not interested in actual differences in those files, and only wish to check the return value of cmp
, this is the right way:
cmp --silent "${backup_file}.xz" "${backup_file}.xz.dec" &&
echo "Files are identical." ||
print_error "Failed to compare files!"
Re-write awkward texts
I have re-written most of them, but one example:
Comparing your un-encrypted, compressed, archived, directory file
could sound better as
CMP is comparing the un-encrypted compressed file
Current code looks like this
#!/bin/sh
# Treat unset variables as an error when substituting
set -o nounset
[ "$#" -eq 0 ] && echo "You need to give me one directory!" && exit 1
[ "$#" -gt 1 ] && echo "Multiple arguments are not supported!" && exit 1
[ ! -d "$1" ] && echo "This is not a directory!" && exit 1
[ ! -w "$PWD" ] && echo "The current directory is not writable by you!" && exit 1
# In order to compress many directories with the same password,
# I decided to create a password file to avoid too many annoying prompts
passwd_file="/home/vlastimil/.blablablabla"
[ ! -f "$passwd_file" ] && echo "The password file does not exist!" && exit 1
dir=$(basename "$1")
today=$(date +%Y-%m-%d)
backup_dir="${dir}_${today}"
# backup_dir="${dir}"
backup_file="${backup_dir}.tar"
# TAR is archiving the directory into the following temporary file,
# it gets deleted on successful processing
[ -f "${backup_file}" ] && echo "File ${backup_file} exists, exiting." && exit 1
# XZ is compressing the archive into the following temporary file,
# it gets deleted on successful processing
[ -f "${backup_file}.xz" ] && echo "File ${backup_file}.xz exists, exiting." && exit 1
# OpenSSL is decrypting the file (for verification) into the following temporary file,
# it gets deleted on successful processing
[ -f "${backup_file}.xz.dec" ] && echo "File ${backup_file}.xz.dec exists, exiting." && exit 1
# OpenSSL is encrypting the compressed file into the following permanent file,
# this is the result of successful processing
[ -f "${backup_file}.xz.enc" ] && echo "File ${backup_file}.xz.enc exists, exiting." && exit 1
# SHA512SUM is computing a hash sum of the encrypted file into the following permanent file,
# this is the result of successful processing
[ -f "${backup_file}.xz.enc.SHA512SUM" ] && echo "File ${backup_file}.xz.enc.SHA512SUM exists, exiting." && exit 1
bold=$(tput bold)
no_color=$(tput sgr0)
red=$(tput setaf 1)
#blue=$(tput setaf 4)
#cyan=$(tput setaf 6)
green=$(tput setaf 2)
white=$(tput setaf 7)
yellow=$(tput setaf 3)
#magenta=$(tput setaf 5)
action_number_color="${bold}${red}"
action_color="${bold}${yellow}"
file_color="${bold}${white}"
success_color="${bold}${green}"
print_action()
{
echo
echo "${action_number_color}$1${no_color}"
echo
}
print_error()
{
echo
echo "$1"
exit 1
}
#------------------------------------------------------------------------------------------------------------------
print_action "1/7:${action_color}
TAR is archiving the directory
${file_color}${dir}${action_color}
into
${file_color}${backup_file}"
tar --create --file="${backup_file}" "$1" --totals --verify ||
print_error "TAR failed to archive the directory!"
#------------------------------------------------------------------------------------------------------------------
print_action "2/7:${action_color}
XZ is compressing the archive
${file_color}${backup_file}${action_color}
into
${file_color}${backup_file}.xz"
xz --format=xz --check=sha256 -9 --threads=8 --keep --verbose --extreme "${backup_file}" ||
print_error "XZ failed to compress the backup file!"
#------------------------------------------------------------------------------------------------------------------
print_action "3/7:${action_color}
OpenSSL is encrypting the compressed file
${file_color}${backup_file}.xz${action_color}
into
${file_color}${backup_file}.xz.enc"
pv --progress --timer --eta --rate --average-rate --bytes "${backup_file}.xz" |
openssl enc -aes-256-cbc -md sha256 -salt -out "${backup_file}.xz.enc" -pass file:"$passwd_file" 2> /dev/null ||
print_error "OpenSSL failed to encrypt the compressed file!"
#------------------------------------------------------------------------------------------------------------------
print_action "4/7:${action_color}
SHA512SUM is computing a hash sum of the encrypted file
${file_color}${backup_file}.xz.enc${action_color}
into
${file_color}${backup_file}.xz.enc.SHA512SUM"
sha512sum --binary "${backup_file}.xz.enc" > "${backup_file}.xz.enc.SHA512SUM" ||
print_error "SHA512SUM failed to compute the hash sum!"
#------------------------------------------------------------------------------------------------------------------
awk '{ print $1 }' "${backup_file}.xz.enc.SHA512SUM"
#------------------------------------------------------------------------------------------------------------------
print_action "5/7:${action_color}
OpenSSL is decrypting the file (for verification)
${file_color}${backup_file}.xz.enc${action_color}
into
${file_color}${backup_file}.xz.dec"
pv --progress --timer --eta --rate --average-rate --bytes "${backup_file}.xz.enc" |
openssl enc -aes-256-cbc -md sha256 -salt -out "${backup_file}.xz.dec" -d -pass file:"$passwd_file" 2> /dev/null ||
print_error "OpenSSL failed to decrypt the encrypted file!"
#------------------------------------------------------------------------------------------------------------------
print_action "6/7:${action_color}
CMP is comparing the un-encrypted compressed file
${file_color}${backup_file}.xz${action_color}
with
${file_color}${backup_file}.xz.dec"
cmp --silent "${backup_file}.xz" "${backup_file}.xz.dec" &&
echo "Files are identical." ||
print_error "Failed to compare files!" &&
{
print_action "7/7:${action_color}
Cleaning up"
rm "${backup_file}" &&
echo "${backup_file} removed"
rm "${backup_file}.xz" &&
echo "${backup_file}.xz removed"
rm "${backup_file}.xz.dec" &&
echo "${backup_file}.xz.dec removed"
echo
echo "${success_color}Your directory ${file_color}${dir}${success_color} has been successfully stored as ${file_color}${backup_file}.xz.enc${no_color}"
exit 0
}
And how it appears in Cygwin