blob: 5af4cd613e561868857118fd9729f52e7b9b3a89 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
# Basic bash configuration for scripts.
# Copyright 2020-2024 Einhard Leichtfuß
#########################
## Minimum Bash version
if [ -z "$BASH_VERSINFO" ]
then
printf 'Failed: $BASH_VERSINFO undefined or null.\n' >&2
exit 1
fi
if [[ ${BASH_VERSINFO[0]:-0} -lt 5
|| ( ${BASH_VERSINFO[0]:-0} -eq 5 && ${BASH_VERSINFO[1]:-0} -lt 2 )
]]
then
printf 'Failed: Bash version < 5.2.\n' >&2
exit 1
fi
###################################
## Error and termination handling
# See `/docs/error-handling.md` on limitations and annoyances.
## What to consider as an error.
# Accessing unset variables is an error.
set -o nounset
# No `pipefail` (default).
# - Enabling this might, in particular, cause unexpected issues in `if`
# statements.
# - Enable in a subshell whereever necessary.
## How to act on error.
function basic::print_stacktrace()
{
local -ri offset="$1"
local -i i
local -a args=()
for (( i = offset + 1; i < ${#BASH_SOURCE[@]} - 1; i++ ))
do
# See also the `caller` bash builtin.
args+=( "${BASH_SOURCE[i]} ${BASH_LINENO[i-1]} ${FUNCNAME[i]}" )
done
args+=( "${BASH_SOURCE[i]} ${BASH_LINENO[i-1]} <main>" )
basic::stacktrace_prettyprint "$BASH_SUBSHELL" "${args[@]}"
return 0
}
# Default function to pretty-print stack trace.
# - To be redefined if desired.
function basic::stacktrace_prettyprint()
{
local -ri subshell_id="$1"
shift
local -i i=$#
local msg
for msg
do
printf 'FAILED (%d, %d): %s\n' $subshell_id $((--i)) "$msg" >&2
done
return 0
}
# On ERR, print stack trace and exit non-zero.
trap 'basic::print_stacktrace 0; exit 1' ERR
# Inherit traps on ERR.
set -o errtrace
# Exit on ERR.
# - This is mostly made redundant by the ERR trap (which causes an exit).
# - However, in some cases, the ERR trap does not apply, while `errexit` does:
# - `var[0]=(foo bar)`, when not in a subshell.
# - Same for an associative array.
# - It is unclear why `errexit` and the ERR trap apply on different
# conditions.
# - `inherit_errexit` seems indeed irrelevant in our case, but we enable it
# for consistency.
# - Note: `inherit_errexit` is similar to `errtrace`.
# - See also: `/docs/error-handling.md#Array_variables`
set -o errexit
shopt -s inherit_errexit
## How to act on exit.
# Default on_exit() function.
# - To be redefined if desired.
function basic::on_exit()
{
return 0
}
trap 'basic::on_exit' EXIT
########################
## Other shell options
# Disable globbing; set good defaults for when temporarily enabled.
# - `extglob` has an effect regardless.
set -o noglob
shopt -s nullglob dotglob globasciiranges globstar extglob globskipdots
# Print an error message upon `shift`-ing "too far" (causes ERR regardless).
shopt -s shift_verbose
# Expand associative array subscripts only once.
shopt -s assoc_expand_once
# Do not let `source' use PATH.
shopt -u sourcepath
##################
## Other options
# Explicitly set the expected default umask.
umask 022
# vi: ft=bash ts=2 sw=0 et
|