ebash

enhanced bash

Home Table of Contents GitHub

ebash Style

These are the styles we use when writing code in ebash, and frequently in related code using ebash.

General Formatting

The top level of code belongs at the far left, and each compound statement deserves an indent of 4 spaces.

if true; then
    if something_else; then
        something
    fi
fi

NOTE: We use spaces instead of tabs in all ebash code. The only exception to this is that here docs and here strings (using <<- operator) must use tabs because that is what bash requires.

We also try to keep lines under 120 characters and indent for lines that are continuations of the previous the same amount.

some_really_long_command --with --long --args \
    | grep pattern                            \
    | tail

When we escape very long lines, we try to align the escape characters. This helps us visually scan code and know that the escape characters are present on each line. One place you’ll see a lot of this is with opt_parse:

$(opt_parse \
  "+best             | Use the best compression (level=9)."                              \
  "+bootable boot b  | Make the ISO bootable (ISO only)."                                \
  "+delete           | Delete the source files after successful archive creation."       \
  "+dereference      | Dereference (follow) symbolic links (tar only)."                  \
  ":directory dir  d | Directory to cd into before archive creation."                    \
  ":exclude x        | List of paths to be excluded from archive."                       \
  "+fast             | Use the fastest compression (level=1)."                           \
  "+ignore_missing i | Ignore missing files instead of failing and returning non-zero."  \
  ":level l=9        | Compression level (1=fast, 9=best)."                              \
  "+nice n           | Be nice and use non-parallel compressors and only a single core." \
  ":type t           | Override automatic type detection and use explicit archive type." \
  ":volume v         | Optional volume name to use (ISO only)."                          \
  "dest              | Destination path for resulting archive."                          \
  "@srcs             | Source paths to archive.")

Naming

Spell out your words. Lvng out vwls is cnfsng. (Leaving out vowels is confusing). Avoid abbreviations unless they’re really common (e.g. num for number) or they’re used all over the place (e.g. cmd for command). Try to name based on the purpose of something rather than its type (e.g. string and array aren’t particularly descriptive names).

Bash provides no namespaces, so when we have a group of related functions, we’ll frequently use a common term as the first word of the name to group them and avoid collisions. For that first word, we do occasionally use abbreviations as we don’t want them to cause the names to increase to ridiculous lengths.

For instance, you’ll find functions with these names in ebash:

Curly Braces

When reading the value of a variable, use curly braces. For example, use ${VAR} and not $VAR.

Exceptions:

if/then and do Alignment

Put then and do on the same line as the statement they belong to. For instance:

if true; then
    something
fi

for i in "${array[@]}"; do
    something
done

Always use [[ and ]] instead of [ and ]

Bash provides [[ because it’s easier to deal with, has more functionality such as regular expression matching, and reduces the amount of quoting you must do to use it correctly.

[ is a posix-standard external binary. [[ is a bash builtin, so it’s cheaper to run. The builtin is also able to give you syntactic niceties. For instance, you need to quote your variables much less. This is safe. Whereas the same thing with the [ command would not be.

Safe:

[[ -z ${A} ]]

NOT Safe:

[ -z ${A} ]

Aside from posix shell compatibility (which is not a concern when using ebash), there is no downside.

Local Variables

Every variable that can be declared local must be declared local.

If you don’t tell bash to use local variables, it assumes that all of the variables you create are global. If someone else happens to use the same name for something, one of you is likely to stomp on the value that the other set.

Note that both local and declare create local variables. ebash helpers such as opt_parse and tryrc create local variables for you, too.

One place that it’s really easy to accidentally not use a local variable is with a bash for loop.

# Note: index here is NOT LOCAL
for index in "${array[@]}" ; do
    something
done

You must specifically declare for loop index variables as local.

local index
for index in "${array[@]}"; do
  something
done

NEVER change IFS

Like most other bash code, ebash is written under the assumption that IFS is at its default value. If you change the value of IFS and call any ebash code, expect things to break most likely in subtle ways.

Markdown Style

Adhere to the guidance in the fantastic Markdown Style Guide. Particular choices we have made to use ebash: