Shell Scripting for UNIX-like Systems

Page content

Notes on shell scripting with Bash and other UNIX shells.

The Shebang Line: /bin/sh and /bin/bash

Start your shell scripts with the shebang sh, unless you have a specific reason to require another shell. Linux and other UNIX-like systems all include a symbolic link for /bin/sh that points to the default shell for the operating system.

If you use the sh shebang, shells will detect this, and interpret your script using the syntax of the Bourne shell, without any extra features. This means that the script should run correctly in all of the shells that supports the Bourne syntax.

The shebang line for sh is:

#!/bin/sh

The shells that support Bourne syntax include Bash, Z shell (zsh), the Debian Almquist shell (dash), and the Almquist shell that is part of Busybox.

Most Linux systems use Bash for shell scripts. Current versions of macOS also provide Bash, but macOS Catalina uses Z shell by default. Debian-based systems use the Dash shell for sh scripts, and Bash for interactive shells. Alpine Linux uses Busybox.

If you need to use features that are specific to Bash, use the bash shebang. This means that the script will be run by Bash, rather than the default shell.

This Stack Overflow answer on bash vs .sh provides more details.

Debian-based systems, such as Ubuntu, provide the checkbashisms tool for you to be able to test scripts for portability.

Enabling Better Error Handling with set

Always use a set command at the start of your scripts, immediately after the shebang line:

set -eu

Bash and some other shells provide the -o pipefail option, but it is not part of the POSIX standard.

set -euo pipefail

In addition, add the -E option to ensure that ERR traps catch errors from functions and subshells:

set -Eeuo pipefail

To print each command that the shell runs as it executes, add the -x option:

set -xeuo pipefail

Use ShellCheck to Validate Your Scripts

The ShellCheck utility will spot common mistakes and issues in your shell scripts. Always use this tool, because it will enable you to avoid whole classes of problem. For example, ShellCheck considers unquoted strings to be an issue, because of the risk of wordsplitting.

Use sh to Format Your Shell Scripts

The sh utility will format your shell scripts to be consistent.

Startup Scripts

Each UNIX shell runs a specific set of scripts each time that starts. Use these default scripts to set environment variables.

Bash Startup Scripts

Bash runs different scripts, depending on how is started:

  • Started as an interactive non-login shell, it runs the .bashrc scripts. The terminal windows on a Linux graphical desktop are non-login shells.
  • Started as an interactive login shell, it runs .bash_profile, .bash_login, and .profile (in that order).
  • Started as a non-interactive, non-login shell, it runs the script specified by the BASH_ENV environment variable.
  • Started with sh, it runs /etc/profile and ~/.profile scripts.

The global system copy of each default script will be in the /etc directory, and there may be a second script with the same name in the home directory of the current user. Both of these scripts will run.

For convenience, operating system vendors provide default scripts that call other scripts.

Standard Environment Variables on Linux

The Debian Wiki page lists these standard environment variables:

  • PATH Colon separated list of directories to search for commands.
  • HOME Current user’s home directory.
  • LOGNAME Current user’s name.
  • SHELL The user’s preferred shell.
  • EDITOR The user’s preferred text editor.
  • MAIL The user’s email inbox location.

Running Commands on Remote Systems with SSH

To run a single command, use the ssh utility:

ssh user1@server1.example "command"

To run multiple commands, use a HERE-doc:

ssh user1@server1.example << HERE
 command1
 command2
HERE

To run a script on a remote system, use SSH to send the contents of the script file to a script interpreter on the remote system. This example uses the bash shell:

ssh user1@server1.example '/bin/bash -s' < scriptfile.sh

The -s option means that the bash shell will run what is sent to it from the standard input.

ssh exits with either the exit status of the remote command, or with status number 255 if an error occurred.

Online Resources

Using the Command-line

Bash Scripting