Bash Control Scripts
Bash works great for "control" scripts, as part of the unix philosophy, to glue a series of steps together and play with the filesystem - try to avoid using it to implement computation directly, there are loads of gotchas that are hard to prevent or identify.
Useful Snippets
What follows are a selection of snippets I find useful, some have their caveats. Feel like something important is missing? Contact me and tell me.
Work Locally
This is incredibly useful for build or run scripts, which need to execute on items relative to where the script itself is.
source_dir="$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)"
cd $source_dir
At any later point you can cd $source_dir
to reset yourself without having to worry about where you have managed to end up. Useful when running intermediate scripts and working inside repositories or in other 'relative path' situations.
Fail Fast
Missing errors introduces bugs. Strict mode is useful but not perfect, read the blog post where I first found it here (by Aaron Maxwell).
set -euo pipefail
$IFS=$'\n\t'
The following assumes you have at least skimmed the blog :- I use -uo pipefail
at all times and will toggle -e
for times when I am expecting an error code. The IFS change is not actually something I will implement until using a loop - I prefer to set it for the specific code than as a general case.
Change the input
Sometimes you want to pretend things were different:
#!/bin/bash
echo "Input: \"$@\""
set -- "Three blind mice"
echo "Out: \"$@\""
Here we manipulate the calling arguments, useful with getopt
and getopts
Less colour is more colour
Handy tip, have less output in colour:
jq -C '.' | less -R
- less uses the -R switch, allowing "raw" control characters
- jq uses the -C switch, forcing colouring even though it is piping
git -c color.status=always status | less -R
- git uses the
-c
parameter before a temporary configuration change. The arguments passed here could be put into the.gitconfig
file
Many programs suppress colourised output if they detect they are being redirected, if you are using the -R
switch with less and the output isn't colourful then you need to enable switches earlier on in the pipe.
.bashrc git branch
It is often useful to display your current git branch in your prompt - but not obvious how to do it.
Embedding function calls in the prompt
Example basic prompt:
export PS1="${USER}@${HOST} \w\n"
Example prompt with embedded function call:
export PS1="${USER}@${HOST} \$(date -I) \w\n"
In the example with the embedded call, notice how it is backslash escaped.
Getting the current git branch
git_branch() {
git status --porcelain -b 2> /dev/null | grep -Po "(?<=^## )[^\.]+" 2>/dev/null
if [ "$?" -gt 0 ]; then
echo "--"
fi
}
git branch() {
# Save original directory
local dir="`pwd`"
# Move upwards through the directory tree until a .git directory is found
while [ "`pwd`" != "/" ] && ! [ -e ".git" ]; do cd ..; done
# If it has been found, echo the branch of HEAD, else echo "--"
if [ -e ".git" ]; then grep -Eo "[^/]+$" .git/HEAD; else echo "--"; fi
# Restore original directory
cd "$dir"
}