User Tools

Site Tools


software:shell

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 session2) 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

You may use any of these shells - be advised, however, that:

  • We only support Bash.
  • Some Cluster features (e.g. the environment exported by SLURM) might not be available).

Best Practices

This is a completely arbitrary list - and only on Bash! We make no claim for it to be complete.

  1. Always comment your script

    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.
  2. 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:
    #let script exit if a command fails
    set -o errexit 
    OR
    set -e


    Add || true to commands that you allow to fail.

  3. 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:
    #let script exit if an unsed variable is used
    set -o nounset
    OR
    set -u
  4. Make broken pipes fail

    Use set -o pipefail in scripts to catch command fails in e.g. in first_command | grep <pattern>. The exit status of the last command that threw a non-zero exit code is returned.
  5. 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.
  6. Surround your variables with quotes

    For example in
    if [ "${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:

    if [ "${NAME:-}" = "Kevin" ]

    will set $NAME to be empty if it's not declared. You can also set it to noname like so

    if [ "${NAME:-noname}" = "Kevin" ]
  7. 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:
    function check_integrity(){
    	command1; 
    	command2;
    }

    OR

    check_integrity(){
    	command1; 
    	command2;
    }

    For single line code, use termination characters after each command like this:

    check_integrity(){ command1; command2; }
  8. Use $(command) instead of legacy `command` for Substitution

    Command substitution replaces a command with its output. Use $(command) instead of backquotes `command` for command substitution.

    This even allows nesting commands without loosing your sanity:
    parent=$(basename $(dirname $PWD))
  9. 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:
    readonly 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.

Integrety 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.

1)
In case one is missing or you would like to use a different one, let us know.
2)
Some shells provide an -i flag, which can be supplied to enforce an interactive shell.
software/shell.txt · Last modified: 2019/08/20 20:27 by meesters