Bash Scripting: Examples

Hi everyone. I hope you’re still enjoying the strange yet warm September weather! Today’s blog will be the last in this Bash Scripting series, at least for the time being.
In this final edition I have provided two examples of the commands I have written about over the last few weeks, namely ‘mount’, ‘if’ and ‘rsync’ as well as a few others thrown in. These examples are shown as Fraise.app screenshots and explanations below.
Enjoy!

Example 1: The situation

So you’d like a nice easy way to have a reminder pop up in Finder every Friday to remind you to take the Backup tapes home? Try this script below, and schedule it using a Launch Agent to run once a day.
Launch Agent

#!/bin/sh
# Show a message but only on Fridays
today=`date | awk '{print $1}'` 	# <- This takes today's date, grab the first part (the day) and saves it as a varible
#########################################################################################################################################################
if [ $today = Fri ]					# <- This asks if the varible above is the same as "Fri"
	then							# <- This is the action taken if the varible does match "Fri"
		echo "Today is friday"		# <- This displays a message in the terminal window.
		osascript -e 'tell application "Finder"' -e "activate" -e "display dialog "Today is Friday! DO NOT forget to take home the backup tapes!"" -e 'end tell'
									# ^^ This displays a message in the Finder GUI
	else							# <- This is the action taken if the varible does not match "Fri"
		echo "Today is not friday" 	# <- This displays a message in the terminal window.
		osascript -e 'tell application "Finder"' -e "activate" -e "display dialog "Today is not Friday :( No tapes to take home today"" -e 'end tell'
									# ^^ This displays a message in the Finder GUI
fi									# <- This closes the 'if' question

Example 1: Explanation

Here’s a line-by-line run down on what the script is doing:

  • Line 1 – This is the standard opener for bash scripting and tells the script in what shell to run.
  • Lines 2, 4-6, 8, 10, 12, 14, 16, 19, 21, 23, and 26 – These are empty lines purely for making viewing easier. “White Space” (empty lines and tabs) is ignored in bash.
  • Lines 3, 9, 18, and 25 – This are comments preceded with the ‘#’ symbol. These can be used to split up sections of a script or to add notes, but without affecting the script it self.
  • Line 7 – This command will find the current date, cut it down to the first three letters of the day (e.g. “Mon”) and save it for recalling later.
  • Line 11 – This line asks if the ‘variable’ stored in line 7 matches the term “Fri”. This translates to “Is today Friday?”
  • Line 13 – This line tells the script what to run if the question from Line 11 is true. This translates to “Today is Friday, do this”.
  • Line 15 – This command will, if the script is being run in a Terminal window, output the words “Today is Friday” into the window. Alternatively, by adding “ >> ~/Desktop/Fri_message.log” to the end, you could have this output into a log file on the desktop.
  • e.g. echo "Today is friday" >> ~/Desktop/Fri_message.log
  • Line 17 – This line passes information to the Apple Script application. This, in turn, opens a Message window with the content “Today is Friday! DO NOT forget to take home the backup tapes!” shown.
  • Line 20 – This line tells the script what to run if the question from Line 11 is false. This translates to “Today is not Friday, do this”.
  • Line 22 – This command will, if the script is being run in a Terminal window, output the words “Today is not Friday” into the window. Alternatively, by adding “ >> ~/Desktop/Fri_message.log” to the end, you could have this output into a log file on the desktop (example above).
  • Line 24 – This line passes information to the Apple Script application. This, in turn, opens a Message window with the content “Today is not Friday :( No tapes to take home today” shown.
  • Line 27 – This line closes the ‘if’ question and is a requirement if using if. Much the same as using HTML code, you have to close options after you have opened them (e.g. Bold – [b] This is bold [/b] this is not).

Example 2: The situation

So, this time you’re looking to mount an AFP share, sync files to it from a local folder, error check this and unmount the share? Here you go:
rsync mount

#!/bin/sh
# Sync files from location A (local) to location B (File server)
Server="file-server.amsys.internal"			# <- This loads in a varible called "Server" of the server address
Username="file-user"						# <- This loads in a varible called "Username" of the server share username
Password="12345"							# <- This loads in a varible called "Password" of the server share password
Share="test_backup"							# <- This loads in a varible called "Share" of the server share name
Source="/Users/test/Desktop/"				# <- This loads in a varible called "Source" of the place to sync files from
Destination="/Volumes/test/Desktop/"		# <- This loads in a varible called "Destination" of the place to sync files to
#########################################################################################################################################################
echo "Make Share folder and mount volume"	# <- This echos the information between the speech marks into the terminal window
mkdir /Volumes/test_backup					# <- This makes a directory (folder) in Volumes for the share to mount on.
sleep 2										# <- This pauses the script for 2 seconds
mount_afp "afp://$Username:$Password@$Server/$Share" /Volumes/test_backup
											# ^^ This mounts the "Share" on the "Server" using the "Username" and "Password" onto the folder in Volumes
echo "Volume mount complete"				# <- This echos the information between the speech marks into the terminal window
echo "Starting syncing"						# <- This echos the information between the speech marks into the terminal window
rysnc -azv $Source $Destination				# <- This syncs the files from "Source" to "Destination" without deleting any items
if [$? = 0]									# <- This asks if the exit code of the sync is '0' (and so fine)
	then									# <- This is the action taken if the exit code is '0'
		echo "Sync completed without error"	# <- This echos the information between the speech marks into the terminal window
	else									# <- This is the action taken if the exit code is not '0'
		echo "Sync completed, but with an error" # <- This echos the information between the speech marks into the terminal window
fi											# <- This closes the 'if' question
umount /Volumes/test_backup

Example 2: Explanation

Here’s a line-by-line run down on what the script is doing:

  • Line 1 – This is the standard opener for bash scripting and tells the script in what shell to run.
  • Lines 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 27, 29, 31, 33, 35, 37, 39, 41, 43 and 45 – These are empty lines purely for making viewing easier. “White Space” (empty lines and tabs) is ignored in bash.
  • Lines 3, 17, and 26 – This are comments preceded with the ‘#’ symbol. These can be used to split up sections of a script or to add notes, but without affecting the script it self.
  • Line 5 – This command will store the server address, for later recalling using the name ‘Server’.
  • Line 7 – This command will store the share username, for later recalling using the name ‘Username’
  • Line 9 – This command will store the share password, for later recalling using the name ‘Password
  • Line 11 – This command will store the share name it self, for later recalling using the name ‘Share’.
  • Line 13 – This command will store the source folder for syncing, for later recalling using the name ‘Source’.
  • Line 15 – This command will store the destination folder for syncing, for later recalling using the name ‘Destination’.
  • Line 19 – This command will, if the script is being run in a Terminal window, output the words “Make Share folder and mount volume” into the window. Alternatively, by adding “ >> ~/Desktop/mount_sync.log” to the end, you could have this output into a log file on the desktop.
  • e.g. echo "Make Share folder and mount volume" >> ~/Desktop/mount_sync.log
  • Line 21 – This command will create a folder (or directory) in /Volumes called ‘test_backup’.
  • Line 23 – This command tells the script to pause here for 2 seconds. This is typically used when instructions can ‘bump’ into each other and you require some ‘breathing space’ in between commands.
  • Line 25 – This command will use the ‘Server’, ‘Share’, ‘Username’ and ‘Password’ variables to mount the server share, authenticated, onto the folder test_backup using afp.
  • Line 28 – This command will, if the script is being run in a Terminal window, output the words “Volume mount complete” into the window. Alternatively, by adding “ >> ~/Desktop/mount_sync.log” to the end, you could have this output into a log file on the desktop (example above).
  • Line 30 – This command will, if the script is being run in a Terminal window, output the words “Starting syncing” into the window. Alternatively, by adding “ >> ~/Desktop/mount_sync.log” to the end, you could have this output into a log file on the desktop (example above).
  • Line 32 – This command will use the ‘Source’ and ‘Destination’ variables to sync the files in the source to those in the destination. Rsync has been set to use the ‘a’, ‘z’ and ‘v’ options, explained below (note: there hs been no automatic deletion enabled. This is for safety reasons):
      • o ‘a’ – Archive mode. This is the same as using ‘rlptgoD’
      • • ‘r’ – Recursive. This will carry out the sync in in folders (or directories) below the starting one.
      • • ‘l’ – Links. This copies symlinks as symlinks, maintaining shortcuts.
      • • ‘p’ – This will preserve the permissions that are set on the source files to those on the destination.
      • • ‘t’ – This will preserve the times (date created and date modified) of the files transferred.
      • • ‘g’ – This will preserve the Group setting (using the UUID of the Group) of the files transferred.
      • • ‘o’ – This will preserve the Owner setting (using the UUID of the owner) of the files transferred.
      • • ‘D’ – Same as --devices --specials.
      • • ‘--devices’ – This will allow the transfer of certain special files.
      • • ‘--specials’ – This will allow the transfer of certain special files.
    • o ‘z’ – Compress. All data is compressed, moved then uncompressed on the fly.
    • o ‘v’ – Verbose mode. This displays a lot more information during the process.
  • Line 34 – This line asks if the variable “$?” matches the term “0”. This varible is automatically produced by every command and stored in $?. This is overwritten each time a command is run. Generally, any exit code of 0 is equal to a completed without error result. This translates to “Did the proceeding command produce an exit code of 0?”
  • Line 36 – This line tells the script what to run if the question from Line 34 is true. This translates to “the rsync exit code is 0, do this”.
  • Line 38 – This command will, if the script is being run in a Terminal window, output the words “Sync completed without error” into the window. In this case, it will only show if the rsync had an exit code of 0. Alternatively, by adding “ >> ~/Desktop/mount_sync.log” to the end, you could have this output into a log file on the desktop (example above).
  • Line 40 – This line tells the script what to run if the question from Line 34 is false. This translates to “the rsync exit code is not 0 (and so has probably failed), do this”
  • Line 42 – This command will, if the script is being run in a Terminal window, output the words “Sync completed, but with an error” into the window. In this case, it will only show if the rsync did not have an exit code of 0. Alternatively, by adding “ >> ~/Desktop/mount_sync.log” to the end, you could have this output into a log file on the desktop (example above).
  • Line 44 – This line closes the ‘if’ question and is a requirement if using if. Much the same as using HTML code, you have to close options after you have opened them (e.g. Bold – [b] This is bold [/b] this is not).
  • Line 46 – This command will unmount the volume we connected way back in Line 25, therefore ensuring the script cleans up after it self.

Summary

There you have it. I hope that gives you some starting points and ideas on ‘the power of scripting!’ As with everything, please test, test, test before rolling any automations out on a live system.
Thanks for viewing the blog posts in this series and I hope they have helped at least some people out there. I will revisit this area at a later date as there is so much more you can do.
I’m still not 100 % sure on what my next blog will be on, but any suggestions are welcome!
Any hints, tips or opinions? Let us know in the comments below and I’ll try to respond to as many as I can.