Skip to content

Shellscript

Shell options

sh

set -o nounset
set -o errexit

Short form:

set -eu

bash

set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'

Short:

set -eu -o pipefail

Reference: redsymbol.net/unofficial-bash-strict-mode

Debug

[ "${DEBUG:=0}" = 1 ] && set -o xtrace

Enable tracing:

$ DEBUG=1 ./script.sh

Cleanup

trap cleanup EXIT

cleanup() {
    # Disable interrupt signal
    trap '' INT
    print_info "cleaning up"
    # Important code goes here
    print_info "done cleaning up"
    # Restore signal handler
    trap - INT
}

Logging

print_info() {
    printf "[\033[1;35m+\033[0m] INFO: %s\n" "${1}"
}

print_warn() {
    printf "[\033[1;33m!\033[0m] \033[1;33mWARNING\033[0m: %s\n" "${1}" >&2
}

print_error() {
    printf "[\033[1;34mx\033[0m] \033[1;34mERROR\033[0m: %s\n" "${1}" >&2
    exit 1
}

Usage

print_usage() {
    cat <<HEREDOC
    usage: $(basename "${0}") <command>
        commands
            foo     do foo action.
            bar     do bar action.
            help    print this help and exit.
HEREDOC
}

Main

command based

sh

foo() { print_info "performing foo." }
bar() { print_info "performing bar" }

if echo "${1:-}" | grep -q "foo\|bar"; then
    # call function and pass it all arguments
    "${@}"
else
    print_usage
    exit 1
fi

bash

foo() { print_info "performing foo." }
bar() { print_info "performing bar" }

if [[ "${1:-}" =~ ^(foo|bar)$ ]]; then
    # call function and pass it all arguments
    "${@}"
else
    print_usage
    exit 1
fi

Parsing arguments

# Parse command line arguments
#
# valid argument formats:
#   -o value
#   -o=value
#   --option value
#   --option=value
#
while true; do
    shiftpos=1

    case "${1:-}" in
        -a|--argument)
            argument="$2"
            shiftpos=2
            ;&
        -a=?*|--argument=?*)
            : "${argument:=${1#*=}}"
            ;;
        -f|--flag)
            flag=1
            ;;

        # handle unknown options
        -?*)
            print_warn "Unknown option '$1'"
            ;;

        # no more options to parse
        *)  break ;;
    esac

    shift $shiftpos
done