Stratus3D

Software Engineering, Web Development and 3D Design

Bash Errexit Inconsistency

I’m a huge fan of the unofficial Bash strict mode. I use it for all my personal scripts as well as for other projects when I can. One part of Bash strict mode is the errexit option, which is turned on by doing set -e or set -o errexit. With errexit turned on, any expression that exits with a non-zero exit code terminates execution of the script, and the exit code of the expression becomes the exit code of the script. errexit is a big improvement, since any unexpected error ends execution of a script rather than being ignored and allowing execution of the script to continue. If you have a command that you expect to fail, you can do one of two things:

# Use the OR operator
maybe_fails || true

# Use the command as an if condition
if maybe_fails; then
  # success
fi

This ensures every command must succeed and the only commands allowed to fail are that are part of expressions designed to handle non-zero exit codes like if statements. If you have a command that you expect to fail and don’t care about the failure you are best off using the OR operator with true as the second command. If you have a command that may fail, and you want to execute code conditional based on the exit code of the command an if statement is the best option. But as I recently learned, there is one pitfall with the way errexit works with functions invoked from if conditions.

The Problem

errexit isn’t used when executing functions inside an if condition. A function executed normally with errexit would return the exit code of the first expression that returned a non-zero exit code, and execution of the function would stop. A function executed inside an if statement with errexit would ignore non-zero exit codes from commands invoked by the function and would continue to execute until a return or exit command is encountered. Here is an example script:

#!/usr/bin/env bash

set -e

f() {
	false
	echo "after false"
}

if f; then
  echo "f was successful"
fi

f

In this code we invoke the function f twice. Once inside the if statement and once by itself as a single expression. You might think this script will not output anything, since the first expression in the function f is false, which is a command that always returns an exit code of 1. However, the output of this script is actually:

after false
f was success

And the exit code of this script is 1, indicating a failure. When f is executed inside an if condition it is considered successful, and both lines of the function are executed. When it is executed outside of an if statement, as we would expect, only the first line of the function is evaluated and the function returns the exit code of the false command, which is always 1.

To sum up, when using errexit, any expression that returns an non-zero exit code will halt execution of the current function and return the non-zero exit code, unless the function is executed from inside an if statement condition, in which case non-zero exit codes are ignored.

The Solution

The solution to this is to simply never invoke functions from within if statement conditionals. Instead the function must be executed before the if statement and the return code must be captured in a variable. Here is the same if statement as above modified to use this approach:

# Execute command and capture exit code, regardless of whether the command succeeded or not
f && exit_code=$? || exit_code=$?

# Use the exit code variable as the condition for the if statement.
if [ "$exit_code" = 0 ]; then
  echo "f was successful"
fi

While this is not very elegant it is easy to use in practice. Since the function is executed outside of the if statement it will always be executed with errexit set as expected.

My Favorite Talks From Strange Loop 2019

I was able to go Strange Loop for the first time this year. I’ve watched a lot of videos of talks from Strange Loop over the last couple years, and was excited to be able to attend this year. It was a great conference with excellent talks on a good variety of topics. I learned a lot and I am really glad I went. The conference was multi-track with up to 8 talks scheduled during each time slot, so there were many talks I missed. Below are my 6 favorite talks from those I attended at the conference. I am sure there are many excellent talks I missed out on, but these were my favorites among the ones I attended.

Probabilistic Scripts for Automating Common-Sense Tasks

My favorite talk from the conference by far. Coming into the talk I didn’t have an experience with probabilistic programming so this talk introduced me to the concepts and as well as Gen, a probabilistic programming system. I was able to learn a lot from this talk and it got me excited about probabilistic programming. I have decided to dedicate some time to learning probabilistic programming.

This talk was a good reminder of the importance of web accessibility. I really enjoyed the topic as it forced me to look at the web differently. Realizing that not everyone can have the same experience on the web reminds me to be more careful about how I design things for the web. This talk introduced my to Pa11y and I’ve started running it on this website.

How to Teach Programming (and Other Things)?

This was an excellent and fun talk. This keynote was probably one of the most thought provoking talks I listened to at the conference. I think it was also one of the most controversial talks that was given at the conference. I had numerous discussions with people at the conference with people about the things I agreed with and the things I didn’t agree with in this talk. Overall it was very thought provoking and very well presented.

New programming constructs for probabilistic AI

Another interesting talk about probabilistic computing. This talk also featured example code written with Gen just like the other talk on probabilistic scripting. This talk presented some very interesting problems and showed how probabilistic programming constructs could be used to solve them without a strong understanding of the underlying mathematics.

Uptime 15,364 days - The Computers of Voyager

An all around fun and informative talk about the design and development of the Voyager space probes. Aaron covers the requirements the project had as well challenges that were encountered in the design and development of the hardware for the probes. I found the details of the redundant computer hardware and the probes' power system to be particularly interesting.

Parser Parser Combinators for Program Transformation

A very interesting talk on tool called comby, which allows for programmatic refactoring of code in any language. comby has been run on code in the top 100 Github projects and produced refactorings that resulted in around 40 merged PRs all without any manual manipulation of the code. comby seems very powerful and I hope ideas like this will become more popular.

Elixir Cheatsheet

Last year I created an Erlang cheatsheet. I’ve used Erlang for quite a while, so I knew exactly what I wanted on the cheatsheet. I’ve only been using Elixir for about a year so it took me a while to figure out what I wanted to include on an Elixir cheatsheet. But I settled on some things that aren’t that complicated, but I know I’ve forgotten many times. The resulting cheatsheet includes tables on sigils, escape codes, metaprogramming constructs, pattern matching on lists, maps, and structs, and list comprehension syntax. This cheatsheet isn’t intended for beginners because it does not cover any of the fundamentals of the language. Just like the Erlang cheatsheet this cheatsheet is designed to be printed on a single sheet of 8.5 by 11 inch paper.

The cheatsheet is available for you to freely print or download at https://stratus3d.com/elixir-cheatsheet/. The source code has been released under the MIT license and is available on GitHub at Stratus3D/erlang-cheatsheet.

I’d really like to hear your thoughts on the cheatsheet. Is there something you think my cheatsheet is missing? Is there something that can be simplified or removed?

Let me know via email. If you want to contribute directly feel free to create an issue or pull request on the GitHub repository.