Jay Taylor's notes

back to listing index

jaytaylor's Bash shell skeleton programming snippets quick reference · GitHub

[web search]
Original source (gist.github.com)
Tags: bash shell github snippets gist skeletons jaytaylor gist.github.com
Clipped on: 2023-07-13

Instantly share code, notes, and snippets.

jaytaylor's Bash shell skeleton programming snippets quick reference

Bash shell skeleton programming snippets

Quick references to common and useful bash programming snippets and boilerplate.

1 #!/usr/bin/env bash
2
3 main() {
4
5 }
6
7 if [ "${BASH_SOURCE[0]}" = "${0}" ] || [ "${BASH_SOURCE[0]}" = '--' ]; then
8 set -o errexit
9 set -o pipefail
10 set -o nounset
11
12 if [ "${1:-}" = '-v' ]; then
13 echo 'INFO: Verbose output enabled' 1>&2
14 shift
15 set -o xtrace
16 fi
17
18 main "$@"
19 fi
1 #!/usr/bin/env bash
2
3 ts() { date -u +'%Y-%m-%dT%H:%M:%S%z'; }
4 log_debug() { echo "$(ts) DEBUG: $*" 1>&2; }
5 log_info() { echo "$(ts) INFO: $*" 1>&2; }
6 log_warn() { echo "$(ts) WARN: $*" 1>&2; }
7 log_error() { echo "$(ts) ERROR: $*" 1>&2; }
8 die() { log_error "$*"; exit 1; }
9
10 export -f ts
11 export -f log_debug
12 export -f log_info
13 export -f log_warn
14 export -f log_error
15 export -f die
16
17 usage() { echo "usage: $0 [-v?] ..."; }
18
19 main() {
20 if [[ "${1:-}" =~ ^(-h|--help)$ ]]; then
21 usage
22 return 0
23 fi
24 }
25
26 if [ "${BASH_SOURCE[0]}" = "${0}" ] || [ "${BASH_SOURCE[0]}" = '--' ]; then
27 set -o errexit
28 set -o pipefail
29 set -o nounset
30
31 if [ "${1:-}" = '-v' ]; then
32 log_debug 'verbose mode enabled'
33 shift
34 set -o xtrace
35 fi
36
37 main "$@"
38 fi
1 #!/usr/bin/env bash
2
3 set -o errexit
4 set -o pipefail
5 set -o nounset
6
7 ts() {
8 date -u +'%Y-%m-%dT%H:%M:%S%z'
9 }
10
11 log_debug() {
12 echo "$(ts) DEBUG: $*" 1>&2
13 }
14
15 log_info() {
16 echo "$(ts) INFO: $*" 1>&2
17 }
18
19 log_warn() {
20 echo "$(ts) WARN: $*" 1>&2
21 }
22
23 log_error() {
24 echo "$(ts) ERROR: $*" 1>&2
25 }
26
27 die() {
28 log_error "$*"
29 exit 1
30 }
31
32 export -f ts
33 export -f log_debug
34 export -f log_info
35 export -f log_warn
36 export -f log_error
37 export -f die
38
39 # n.b. alternate one-liner hack form:
40 # eval "$(for x in info warn error; do echo -e "log_${x}() { echo "$(ts) $(echo ${x} | tr [:lower:] [:upper:]): $*"; };"; done)"
41
42 if [ "${1:-}" = '-v' ]; then
43 log_debug 'verbose mode enabled'
44 shift
45 set -o xtrace
46 fi
47
48 usage() {
49 echo "usage: $0 [-v?] ..."
50 }
51
52 main() {
53 if [[ "${1:-}" =~ ^(-h|--help)$ ]]; then
54 usage
55 return 0
56 fi
57 }
58
59 # TODO: Revisit this, behavior seems different from what I observed on
60 # Kubernetes last week. Currently not working properly.
61 ## n.b. Checking for '--' will activate main in cases where the script body has
62 ## been passed in as a string argument.
63 ##
64 ## Example:
65 ## bash -c 'echo "args="$@" BASH_SOURCE[0]=""${BASH_SOURCE}"""' -- -v
66
67 if [ "${BASH_SOURCE[0]}" = "${0}" ] || [ "${BASH_SOURCE[0]}" = '--' ]; then
68 main "$@"
69 fi
1 #!/usr/bin/env bash
2
3 set -o errexit
4 set -o pipefail
5 set -o nounset
6
7 if [ "${1:-}" = '-v' ]; then
8 echo 'DEBUG: verbose mode enabled' 1>&2
9 shift
10 set -o xtrace
11 fi
12
13 die() {
14 echo "ERROR: $*" 1>&2
15 exit 1
16 }
17 export -f die
18
19 usage() {
20 echo "usage: $0 [-v?] ..."
21 }
22
23 main() {
24 if [[ "${1:-}" =~ ^(-h|--help)$ ]]; then
25 usage
26 return 0
27 fi
28 }
29
30 if [ "${BASH_SOURCE[0]}" = "${0}" ] || [ "${BASH_SOURCE[0]}" = '--' ]; then
31 main "$@"
32 fi

Safe for-loop for find output

https://stackoverflow.com/a/9612232/293064

find '.' -print0 | while IFS= read -d '' -r line; do
    echo "line=${line}"
done

Bash verbose xtrace mode

if [ "${1:-}" = '-v' ]; then
    echo 'DEBUG: verbose mode enabled' 1>&2
    set -o xtrace
    # n.b. trap is probably pointless here.  Use at your own discretion.
    trap 'set +o xtrace' EXIT
    shift
fi

Fancy log messaging with source file, function name, and line number incorporated.

# Logging message which includes the source file, function name, and line number.
echo "DEBUG: $(basename "${BASH_SOURCE}"):${FUNCNAME[0]}:${LINENO}: This is a log message" 1>&2

Obtain script directory

BASEPATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"

cd "${BASEPATH}"

Bash main()

Bash equivalent to if __name__ == '__main__': in Python.

n.b. The '--' part needs to be revisited. Yesterday (Sunday 2020-02-09) I was unable to reproduce the behavior previously observed in Kubernetes a few weeks ago.

if [ "${BASH_SOURCE[0]}" = "${0}" ] || [ "${BASH_SOURCE[0]}" = '--' ]; then
    main "$@"
fi

Bash pop last argument / reverse_shift

This can also be thought of as a reverse of the shift command.

Works for both scripts and functions.

Credit: Source

last="${@:$#}"

set -- "${@:1:$(($#-1))}"

trappend: Set or append command to trap signal handler

# trappend is like trap, with the addition  that if there is an existing trap
# already set, it will append the new command(s) without clobbering the
# pre-existing trap orders.
#
# n.b. Won't work for RETURN (hopefully this is somewhat obvious ;).
#
# usage: trappend cmds.. SIGNAL
trappend() {
    local sig
    local existing

    # n.b. Reverse-shift operation.
    sig="${*:$#}"
    set -- "${@:1:$(($#-1))}"

    if [ "${sig}" = 'RETURN' ]; then
        echo 'ERROR: trappend: SIGNAL value cannot be "RETURN"' 1>&2
        return 1
    fi

    if [ -n "$(trap -p "${sig}")" ]; then
        existing="$(trap -p "${sig}" | sed "s/^trap -- '(.*)' ${sig}$/1/");"
    fi

    # shellcheck disable=SC2064
    trap "${existing:-}$*" "${sig}"
}

Example usage

trappend 'echo hello 3' EXIT
trappend 'echo hello 4' EXIT

echo hello 0
echo hello 1

Output:

hello 0
hello 1
hello 3
hello 4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Footer

© 2023 GitHub, Inc.