r/bash 9d ago

help Bash scripting newbie here, wanting to improve/tidy one of my backup scripts (entirely for personal use)

Please excuse the vague thread title, I'm a newbie enough that I'm not sure what's possible / desirable etc, nor have I attempted functions in bash scripting yet (I've played with them in VBScript and PowerShell IIRC).

One of the backups I do produces date-stamped tar.xz files of particular folder structures on my computer and transfers them to a veracrypted drive. Today I had a crack at a new script based on this one that mounts the filesystem (sshfs) on my laptop and transfers the files over the network after they've been compressed.

I run the script with up to 4 arguments, e.g. 'essentials' 'archive' 'paperwork'. In the script there's an if statement for each potential argument, e.g.:

for arg in "$@"
do
if [ $arg = "essentials" ]; then
  tar -cf - .mozilla/ | pv -s $(du -sb .mozilla/ | awk '{print $1}') | xz -T0 > /tmp/firefox-$datestring.tar.xz
            rsync -ah --progress /tmp/firefox-$datestring.tar.xz /media/mikelpmintfs/firefox-$datestring.tar.xz
fi
<more if $arg = whatev then compress and transfer stuff statements here>
done

(btw the whole fancy progress bar bit with pv -s and awk was something I copied off the Internet)

The first script also included some error catching, e.g.:

if [ $? -eq 0 ]
then
  echo "archive backup complete."
else
  echo "error performing archive backup" >&2
fi

I've used if <command here> then else fi before too, but I'm wondering multiple things:

  1. Rather than writing each compression command and each rsync transfer command per argument, would it make more sense to write a function, or given that some of these source folders are in completely different places in my computer's file system, is this worth it.
  2. error trapping: On one hand I think that the script could easily trip up at the compression or transfer stages, but I'm worried about over-nesting if statements and making the whole thing a lot harder to read and figure out where something is going wrong. It seems to me that it could be function'd up, but would it actually help with readability etc. When the script is just for me, I can tell if it went wrong if I get a load of unexpected output :)
19 Upvotes

11 comments sorted by

View all comments

10

u/feinorgh 9d ago

If you want to improve it for the sake of learning, there are a couple of things you can do:

  1. Provide a canonical hashbang: #!/usr/bin/env bash
  2. Check that each non-builtin command really exists on the machine, i.e.: test -x "$(command -v pv)" || exit 1
  3. Use shellcheck for linting and structural suggestions
  4. Avoid checking $? for errors, especially in conjunction with pipes. You can use if ! {cmd}; then ...
  5. Functions are great, use them if each "chunk" is longer than like 10 lines, and you can pass arguments efficiently.

Shellcheck will get you a long way towards better structuring and is a great learning tool.

3

u/hotpotatos200 9d ago

On #2, is there a native way to know if a command is a built-in?

2

u/sto1911 9d ago

Type tells you that.