Shells
Scripting Bash
Bash - or Bourne Again SHell - is the standard shell on our high-performance clusters. We do not attempt to provide full documentation, here, in the wiki. Instead, we like to point to a few great resources:
Both are dated, but still good.
Our Courses
As our HPC introductory course and many others heavily rely on Bash, we provide introductory courses for Bash (dubbed “Bash-Crash”), too. These are intended to provide the background for the HPC introductory course (and any HPC computing) and are intended for those (employees and students in Rhineland Palatinate, alike) with an interest in HPC. You can enroll here .
Other Shells
Some projects suggest or impose to use a different shell. This is, of course, possible on our systems, too.
List of available shells1 and the shebang to use:
Shell | Call for interactive session* | Shebang |
---|---|---|
Bourne Again SHell (Bash) | $ bash | #!/bin/bash |
C-Shell | $ csh | #!/bin/csh |
Korn Shell | $ ksh | #!/bin/ksh |
TENEX-C-Shell | $ tcsh | #!/bin/tcsh |
Z-Shell | $ zsh | #!/bin/zsh |
- Some shells provide an
-i
flag, which can be supplied to enforce an interactive shell.
- We only support Bash.
- Some cluster features (e.g. the environment exported by SLURM) might not be available.
If you choose to use a different shell - in this example zsh
– you can try this snippet (in bash
):
It activates the zsh
, e.g. upon login, when placed in the .bashrc
-file. Calling
will let you return to bash
at any time.
Best Practices
- Always comment your code:
This is a recommended practice which is not only applied to shell scripting but all other kinds of programming. Writing comments in a script helps you or some else going through your script understand what the different parts of the script do.
For starters, comments are defined using the#
sign. - Make a script exit when it fails:
Sometimes bash may continue to execute a script even when a certain command fails, thus affecting the rest of the script (may eventually result in logical errors). Use the line below to exit a script when a command fails:bash #let script exit if a command fails set -o errexit OR set -e
Add|| true
to commands that you allow to fail. - Make a script exit when bash uses an undeclared variable
This is frequently a cause for confusion: Applications crash, when hitting an exception, e.g. an undeclared variable. So does the shell, doesn’t it?
Shells – and Bash – are different. This may be desired or not. Yet, it is not just a source of confusion. It is a cause for a number of tickets (read: help request for the HPC team), too. This is because variables can be undeclared unintentionally. Therefore use the following line to instruct bash to exit a script when it attempts to use an undeclared variable:bash #let script exit if an unsed variable is used set -o nounset OR set -u
- Make broken pipes fail
Useset -o pipefail
in scripts to catch command fails in e.g. infirst_command | grep <pattern>
. The exit status of the last command that threw a non-zero exit code is returned. - Surround your variables with {}
Otherwise bash will try to access the$ENVIRONMENT_app
variable in expansions like/path/$ENVIRONMENT_app
, whereas you probably intended/path/${ENVIRONMENT}_app
. - Surround your variables with quotes
For example inbashif [ "${NAME}" == "Kevin" ]
, because if$NAME
isn’t declared, bash will throw a syntax error (also see nounset). Use:-
if you want to test variables that could be undeclared. For instance:bashif [ "${NAME:-}" == "Kevin" ]
will set$NAME
to be empty if it’s not declared. You can also set it tononame
like sobashif [ "${NAME:-noname}" == "Kevin" ]
- Use functions in Scripts
Except for very small scripts (with a few lines of code), always remember to use functions to modularize your code and make scripts more readable and reusable.
The syntax for writing functions is as follows:
OR
For single line code, use termination characters after each command like this:
- Use
$(command)
instead of legacycommand
for Substitution
Command substitution replaces a command with its output. Use$(command)
instead of backquotescommand
for command substitution.
This even allows nesting commands without losing your sanity:bashparent=$(basename $(dirname $PWD))
- Use read-only to declare static variables
A static variable doesn’t change; its value can not be altered once it’s defined in a script:bashreadonly my_constant=42
There are lots of odds and ends and particularly for new users this can be overwhelming. Be sure to check out our introductory courses .
Integrity Checking of Shell Scripts
However good a writer may be – she will always make mistakes. Now you can always invoke a script with bash -n <script>
to check the script is without errors. Yet, just the other day we installed
“shellcheck”
on the login-nodes. If you run shellcheck <options> <script>
it will spot (most likely) a number of code smells, potential errors and real ones – and sort them according to their respective severity.
Footnotes
In case one is missing or you would like to use a different one, let us know. ↩︎