description:This page gives guidelines and recommandations for shell scripting developement in to-be-continuous.
---
# Shell Scripting Guidelines
This page gives guidelines and recommandations for shell scripting developement in _to be continuous_.
## Introduction
_to be continuous_ templates bring a lot of magic. All this magic is mainly implemented with shell scripts.
Fine! But which kind of shell are we talking about? Is it Bash? Regular C Shell? Something else?
All TBC template scripts are run in container images inheriting one of the three following base images:
```mermaid
---
config:
pie:
textPosition: 0.6
themeVariables:
pieOuterStrokeWidth: "3px"
---
pie
"Alpine (Ash shell)" : 65
"Debian (Bash shell)" : 30
"Fedora (Bash shell)" : 5
```
> [!note]
> TBC will never try to be compliant with other base images than Alpine, Debian or Fedora, and should never make strong assumptions
> on wich base image is used in such or such template (because users might always override the default provided images with their own, and TBC should keep working).
As a conclusion: **_to be continuous_ template scripts must be executable with [Bash](https://www.gnu.org/software/bash/manual/bash.html) and [Ash](https://en.wikipedia.org/wiki/Almquist_shell)**.
Fortunately, [Ash](https://en.wikipedia.org/wiki/Almquist_shell) is a subset of [Bash](https://www.gnu.org/software/bash/manual/bash.html) so all we have to do is to determine which Bash features are supported in Ash, and which aren't. That's the very purpose of this page.
| [advanced conditional expressions][cond-expr] | `[[ -o optname ]]` (true if the shell option _optname_ is enabled)<br/>`[[ -v varname ]]` (true if variable _varname_ is set)<br/>`[[ -R varname ]]` (true if variable _varname_ is set and is a name reference) | ❌ not supported |
| [unset or null substitution expansion][expansion] | `${parameter:−word}` (expands to _word_ if `$parameter` is unset or empty; else `$parameter`) | ✅ supported |
| [unset substitution expansion][expansion] | `${parameter−word}` (expands to _word_ if `$parameter` is unset; else `$parameter`)| ✅ supported |
| [set substitution expansion][expansion] | `${parameter:+word}` (expands to _word_ if `$parameter` is set and not empty; else empty string) | ✅ supported |
All _to be continuous_ templates must use the following [shell options](https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin):
- `set -e`: instructs bash to immediately exit if any command has a non-zero exit status
- `set -o pipefail`: prevents errors in a pipeline from being masked. If any command in a pipeline fails, the pipeline breaks and that return code is used as the return code of the whole pipeline.
### Use `grep` with caution
The `grep` command has a behavior that might cause unexpected behaviors: **returns a non-zero return code when no match is found**.
As a result, due to the [recommended shell options](#shell-options) used in TBC, the following script might fail unintentionally:
```bash
titles=$(grep ^# README.md)
# 💣 the above command will fail and exit the script if no match was found
```
As a conclusion: **don't use `grep` to filter items out of a list**.
For this purpose, prefer using `awk` instead.
The above script can be implemented with `awk`:
```bash
titles=$(awk '/^#/' README.md)
# the above command will never fail, possibly returns an empty string if no match was found
```
**The `grep` command might be used if the return code is tested**:
```bash
if ! grep ^# README.md
then
echo "Your README.md file doesn't contain any title!"
continue
fi
```
### Pattern matching should never be used for pure string matching
The [pattern matching](https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html) implementation on Alpine messes up with filename expansion.
Here is the problem:
```bash
$ docker run --rm -it alpine
# in the container
$ [[ "test" == "te"* ]]; echo $?
0
# 👍 Ok
$ touch te.file
$ [[ "test" == "te"* ]]; echo $?
1
# 💣 due to '"te"*' that messes up with 'te.file'
```
:information_source: this is specific to Alpine Ash, the above behavior is not reproduced in Debian or Fedora Bash.
As a conclusion: **glob patterns should never be used for pure string matching** in _to be continuous_ template scripts.
Instead, prefer using the regex operator.
The above script can be implemented with the [regex operator](https://www.gnu.org/software/bash/manual/bash.html#index-_005b_005b) (`=~`):