While the attribution may be hazy, the notion of laziness being an attribute of a good programmer is popular. I don’t know how good of a programmer I am, but I am really lazy.
So lazy that if I find myself doing something over and over, I write a script to do it for me the next time.
Original: https://xkcd.com/1319/
This is a five-part series:
- Part One (what you’re reading!) has examples for common daily tasks in Git.
- Part Two has similar examples for Rails.
- Part Three has some miscellaneous cases.
- Part Four dissects an example of a failed attempt at a useful script.
- Part Five concludes with a brief discussion of when to use Bash as opposed to some other scripting language. (Spoiler: I’m pro Bash for lots of use cases where many people choose something else.)
Most of the scripts in this series started as one-liners, and the longer ones grew to include more context as I tried to make them more generally applicable.
All of these scripts live in ~/bin
(which is in my path, obviously, I’m too lazy not to have tab completion), and lest you forget, need to be chmod
ed to be executable.
TL;DR for the series:
- Use one-liners to make something easy to remember for things hard to remember
echo -n
to not include a newline is useful for prompting user inputxargs
is your friend!- You don’t have to be a Bash or
sed
orawk
magician to make useful scripts; even knowing only one feature of each of these tools gives you a great deal of power basename
anddirname
are very handy- Prefer absolute paths to relative paths
- Use environment variables to make a script portable
- Using
ssh
with--
to pass a string of commands to execute is great for working with remote systems - Know how to use SSH keys
- Be mindful of potential future growth of files or directories you might be searching or
grep
ing - Use comments (and proofread them!)
- Get a substring:
substr="${string:int_start_pos:int_length}"
e.g.:$ foo='Hello World!' $ echo "${foo:0:1}" H $ echo "${foo:6:6}" World!
- Math!
$ foo=1 $ ((foo += 1)) $ echo "$foo" 2 $ bar=20 $ ((foo = bar + 7)) $ echo "$foo" 27
awk
‘s regex matching is super useful and can make one-liners simpler- If your task involves only filesystem and OS-level tasks, Bash is probably a good fit
- shellcheck.net is your friend
The examples in this series assume a solid understanding of Bash basics, such as pipes, exit statuses, redirecting output, line continuation, and so on. If there’s syntax or usage that isn’t clear, please comment, and I’ll make an update to clarify.
Git
git-one-line-log
I use this one a ton because typing git-o
then tab completion is easier than remembering git log --pretty=oneline
#!/bin/bash git log --pretty=oneline
You could do the same thing by sticking alias git-one-line-log="git log --pretty=oneline"
in your .bash_profile
, but I have it as a script, I’d like to say for consistency, but really because the idea of doing it as an alias didn’t occur to me at the time.
git-branch-cleanup
Beezwax has really mature and standard dev practices, which means that many of our repos have lots of small branches that get automatically deleted once they’re merged. The downside is that your local checkout knows about lots of branches that no longer exist on origin
. Enter git-branch-cleanup
:
#!/bin/bash echo -n "main branch [staging] "; read branch; if [[ -z "$branch" ]]; then branch="staging"; fi git checkout "$branch" \ && git pull \ && git remote prune origin | grep pruned | sed -e 's/.*origin\/\(.*\)/\1/' | xargs git branch -d
echo -n
outputs without a trailing newline, so the prompt looks like this:
$ git-branch-cleanup main branch [staging] _
and I can hit enter to use the staging default, or type something else.
The input branch is whatever branch you generally merge down to (master — or something else — might be more applicable to your workflow).
The git pull
on line 8 is to:
- make sure you’re not on one of the branches that might get deleted, and
- make sure whatever changes have been merged are pulled locally.
Without that you’d get a lot of:
error: The branch 'mobile-logout-link-position' is not fully merged. If you are sure you want to delete it, run 'git branch -D mobile-logout-link-position'.
After pulling changes, git remote prune origin
does exactly what it sounds like, pruning deleted branches on the remote from your local knowledge of origin
. The output of this is grep
ed for “pruned” (the bits from git remote
‘s listing of what it’s pruning), and the sed
substitution lops off everything from the start of the line through origin/
, so all that’s left are the branch names. These are passed as arguments to git branch -d
via xargs
, and you’re left with nice tidy lists of only active branches.
xargs
does way more than what I know to do with it, which is to take lines of standard input and make them into multiple arguments to a single command, but that alone is super powerful.
On to Part Two: Rails