A collection of handy utilities and functions to make bash scripting easier and more fun.

I do a lot of bash shell scripting. Okay, not a lot, but from time to time I find it handy to automate tasks I perform often on my mac. I am no programmer so it took me a while to realize that there was a better method than writing the same code multiple times in many different scripts. I took the common functions and compiled them into a file called utils.sh . Now all I have to do is source (include) this file from any script I write and I have easy access to a number of handy utilities including:

Setting colored and styled text output Performing simple Yes/No confirmations Testing if packages, apps, gems, etc. are installed Sending Pushover notifications Comparing lists to each other

Credit where credit is due

Before I walk through each of the utilities in detail, I need to give clear credit to those who originally wrote the code I have either taken whole-cloth or adapted. I taught myself to program by reading source code of others and adapting what I needed. I have done that liberally here. All code is commented with the originating source. In the interest of providing even more clear credit, here are links to the three sources.

How to use these utilities

I have a single file called utils.sh in which I place all my bash scripting functions. I keep this in file in ~/Library/init/ . Sourcing these utilities is as simple as writing a single line near the top any bash script.

#!/bin/bash source $HOME /Library/init/utils.sh ( some script here )

Colors, Headers, Logging

Styling text output in terminal is important for a usable script. These utilities allow messages to convey meaning through color and iconography.

The functions

# #Set Colors # bold = $( tput bold ) underline = $( tput sgr 0 1 ) reset = $( tput sgr0 ) purple = $( tput setaf 171 ) red = $( tput setaf 1 ) green = $( tput setaf 76 ) tan = $( tput setaf 3 ) blue = $( tput setaf 38 ) # # Headers and Logging # e_header () { printf "

${ bold }${ purple } ========== %s ========== ${ reset }

" " $@ " } e_arrow () { printf "➜ $@

" } e_success () { printf " ${ green } ✔ %s ${ reset }

" " $@ " } e_error () { printf " ${ red } ✖ %s ${ reset }

" " $@ " } e_warning () { printf " ${ tan } ➜ %s ${ reset }

" " $@ " } e_underline () { printf " ${ underline }${ bold } %s ${ reset }

" " $@ " } e_bold () { printf " ${ bold } %s ${ reset }

" " $@ " } e_note () { printf " ${ underline }${ bold }${ blue } Note: ${ reset } ${ blue } %s ${ reset }

" " $@ " }

A sample script

#!/bin/bash source $HOME /Library/init/utils.sh e_header "I am a sample script" e_success "I am a success message" e_error "I am an error message" e_warning "I am a warning message" e_underline "I am underlined text" e_bold "I am bold text" e_note "I am a note"

The output

Seeking User Confirmation

Many bash scripts I write ask for user input before performing a task. Most often these are simple yes/no questions. For example, let’s say you have a script that offers to upload any directory on your desktop to an FTP site. You might want that script to ask you if you want to upload each folder it finds. Here’s some shorthand on how to do that.

The functions

seek_confirmation () { printf "

${ bold } $@ ${ reset } " read -p " (y/n) " -n 1 printf "

" } # Test whether the result of an 'ask' is a confirmation is_confirmed () { if [[ " $REPLY " = ~ ^[Yy] $ ]] ; then return 0 fi return 1 }

A Sample Script

#!/bin/bash source $HOME /.bash_profile source $HOME /Library/init/utils.sh e_header "I am a sample script" seek_confirmation "Do you want to print a success message?" if is_confirmed; then e_success "Here is a success message" else e_error "You did not ask for a success message" fi

The Output

Testing for scripts, packages, OSes

In many scenarios you only want to run a particular section of a script if a certain package or application is installed. For example, don’t run a script that needs Git if Git is not installed. And, don’t run a script that requires a Mac program if you’re on linux. Here’s an easy shorthand to check for installed packages, apps, and OS compatibility.

The functions

type_exists () { if [ $( type -P $1 ) ] ; then return 0 fi return 1 } is_os () { if [[ " ${ OSTYPE } " == $1 * ]] ; then return 0 fi return 1 }

A Sample Script

#!/bin/bash source $HOME /Library/init/utils.sh e_header "I am a sample script" # Check for Git if type_exists 'git' ; then e_success "Git good to go" else e_error "Git should be installed. It isn't. Aborting." exit 1 fi if is_os "darwin" ; then e_success "You are on a mac" else e_error "You are not on a mac" exit 1 fi

The Output

Sending Notifications to Pushover

This function allows you to send notifications to your mobile devices using Pushover’s amazing free service. This comes in very handy if your scripts are running lengthy commands or if they run via Cron.

The function

pushover () { PUSHOVERURL = "https://api.pushover.net/1/messages.json" API_KEY = "your-api-here" USER_KEY = "your-user-key-here" DEVICE = "" TITLE = " ${ 1 } " MESSAGE = " ${ 2 } " curl \ -F "token= ${ API_KEY } " \ -F "user= ${ USER_KEY } " \ -F "device= ${ DEVICE } " \ -F "title= ${ TITLE } " \ -F "message= ${ MESSAGE } " \ " ${ PUSHOVERURL } " > /dev/null 2>&1 }

A Sample Script

#!/bin/bash source $HOME /Library/init/utils.sh pushover "We just finished performing a lengthy task."

The Output

Comparing a list

This bash function is more complicated but I use it all the time. It reads a list of items to be installed and compares it to a list of already existing items on your computer. This allows you only to install the items that are missing.

Complete credit goes to Cowboy who’s code I have lifted entirely.

The function

function to_install () { local debug desired installed i desired_s installed_s remain if [[ " $1 " == 1 ]] ; then debug = 1; shift ; fi # Convert args to arrays, handling both space- and newline-separated lists. read -ra desired < < ( echo " $1 " | tr '

' ' ' ) read -ra installed < < ( echo " $2 " | tr '

' ' ' ) # Sort desired and installed arrays. unset i; while read -r; do desired_s[i++] = $REPLY ; done < < ( printf "%s

" " ${ desired [@] } " | sort ) unset i; while read -r; do installed_s[i++] = $REPLY ; done < < ( printf "%s

" " ${ installed [@] } " | sort ) # Get the difference. comm is awesome. unset i; while read -r; do remain[i++] = $REPLY ; done < < ( comm -13 < ( printf "%s

" " ${ installed_s [@] } " ) < ( printf "%s

" " ${ desired_s [@] } " ) ) [[ " $debug " ]] && for v in desired desired_s installed installed_s remain; do echo " $v ( $( eval echo " \$ {# $v [*]}" ) ) $( eval echo " \$ { $v [*]}" ) " done echo " ${ remain [@] } " }

A Sample Script

In this sample script we are checking a list of Homebrew packages to find out which ones are not already installed.

the recipes list below is the packages we are looking for

list below is the packages we are looking for the line that starts with list= is comparing our list of recipes to the list of packages listed when brew list is entered in your terminal. brew list could just as easily be $(gem list | awk '{print $1}')") to check for installed gems.

is comparing our list of recipes to the list of packages listed when is entered in your terminal. could just as easily be to check for installed gems. Lastly where we are using the echo "$item" to print the results to the screen, we could easily replace that with brew install $item or gem install $item etc.

#!/bin/bash source $HOME /Library/init/utils.sh e_header "Check Homebrew Packages" recipes =( A-random-package bash Another-random-package git ) list = " $( to_install " ${ recipes [*] } " " $( brew list ) " ) " if [[ " $list " ]] ; then for item in ${ list [@] } do echo " $item is not on the list" done else e_arrow "Nothing to install. You've already got them all." fi

The Output

The whole bash utilities script

Here is the complete utils.sh file for you. I hope it helps you as much as it has helped me. As always, if you have questions or comments let me know down below.