Shell script

Directory layout

For builds that involve independent command-line tools, use Make, and follow DataMade’s Making Data Guidelines and Clark Grubb’s Makefile Style Guide, for example: standard_profile_template

If a repository has scripts to set itself up and/or update itself, follow GitHub’s Scripts to Rule Them All, for example: deploy and standard_profile_template

Filename conventions

sh and bash scripts should use the .sh extension, unless they are in a script/ directory.

Shell options

Start shell scripts with set -euo pipefail. If the script explicitly handles unset variables, omit -u. To see which command failed due to the -e option, add -x.

See also

The Set Builtin

Code style

Check /bin/sh scripts using checkbashisms.

Check shell scripts using shellcheck.

Style shell scripts using shfmt: for example, shfmt -w -i 4 -sr (shfmt -f .).

Use:

And:

  • Avoid set -x in scripts run by continuous integration, because it will expand any secret variables

Continuous integration

Create a .github/workflows/shell.yml file. As a base, use:

name: Lint Shell
on: [push, pull_request]
jobs:
  build:
    if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - run: |
          sudo apt update
          sudo apt install devscripts shellcheck shfmt
      - run: checkbashisms $(shfmt -f .)
      - run: shellcheck $(shfmt -f .)
      - run: shfmt -d -i 4 -sr $(shfmt -f .)

Tip

In most cases, you can reuse the shell workflow. For example:

jobs:
  lint:
    uses: open-contracting/.github/.github/workflows/shell.yml@main
    permissions:
      contents: read
    with:
      ignore: file.sh

Maintenance

Find repositories with shell scripts but without shell.yml files:

find . \( -path '*/script/*' -o -name '*.sh' \) ! -path '*/.mypy_cache/*' ! -path '*/node_modules/*' ! -path '*/vendor/*' -exec bash -c 'if [[ -z $(find $(echo {} | cut -d/ -f2) -name shell.yml) ]]; then echo {}; fi' \;

Reference