Revision 9074
Added by Aaron Marcuse-Kubitza over 11 years ago
util.sh | ||
---|---|---|
4 | 4 |
if test ! "$_util_sh_include_guard_utils"; then |
5 | 5 |
_util_sh_include_guard_utils=1 |
6 | 6 |
|
7 |
function extern () { (exec "$@") || return; }
|
|
7 |
function extern() { (exec "$@") || return; } |
|
8 | 8 |
|
9 |
isset () { test "${!1+isset}"; }
|
|
9 |
isset() { test "${!1+isset}"; } |
|
10 | 10 |
|
11 |
realpath () { readlink -f -- "$1"; }
|
|
11 |
realpath() { readlink -f -- "$1"; } |
|
12 | 12 |
|
13 |
include_guard_var () { realpath "$1"|"extern" sed 's/[^a-zA-Z0-9_]/_/g'; }
|
|
13 |
include_guard_var() { realpath "$1"|"extern" sed 's/[^a-zA-Z0-9_]/_/g'; } |
|
14 | 14 |
|
15 |
self_not_included () # usage: if self_not_included; then ... fi
|
|
15 |
self_not_included() # usage: if self_not_included; then ... fi |
|
16 | 16 |
{ |
17 | 17 |
test $# -ge 1 || set -- "${BASH_SOURCE[1]}" |
18 | 18 |
local include_guard="$(include_guard_var "$1")" |
... | ... | |
40 | 40 |
|
41 | 41 |
#### aliases |
42 | 42 |
|
43 |
unalias () { builtin unalias "$@" 2>&- || true; } # no error if undefined
|
|
43 |
unalias() { builtin unalias "$@" 2>&- || true; } # no error if undefined |
|
44 | 44 |
|
45 | 45 |
|
46 | 46 |
#### exceptions |
... | ... | |
56 | 56 |
|
57 | 57 |
# usage: try cmd...; ignore status; if catch status; then ...; fi; end_try |
58 | 58 |
|
59 |
function try () { e=0; "$@" || { export_e; true; }; }
|
|
59 |
function try() { e=0; "$@" || { export_e; true; }; } |
|
60 | 60 |
alias try='declare e; try ' # last space alias-expands next word |
61 | 61 |
|
62 |
catch () { test "$e" -eq "$1"; e=0; }
|
|
62 |
catch() { test "$e" -eq "$1"; e=0; } |
|
63 | 63 |
|
64 |
ignore () { catch "$@" || true; }
|
|
64 |
ignore() { catch "$@" || true; } |
|
65 | 65 |
|
66 | 66 |
alias end_try='rethrow' |
67 | 67 |
alias end_try_subshell='rethrow_subshell' |
... | ... | |
72 | 72 |
|
73 | 73 |
#### integers |
74 | 74 |
|
75 |
let! () { let "$@" || true; } # always returns true; safe to use for setting
|
|
75 |
let!() { let "$@" || true; } # always returns true; safe to use for setting |
|
76 | 76 |
# "If the last ARG evaluates to 0, let returns 1" (`help let`) |
77 | 77 |
|
78 |
bool2int () { try test ! "$1"; echo "$e"; } # empty->0; non-empty->1
|
|
78 |
bool2int() { try test ! "$1"; echo "$e"; } # empty->0; non-empty->1 |
|
79 | 79 |
|
80 | 80 |
|
81 | 81 |
#### arrays |
82 | 82 |
|
83 |
join () { local IFS="$delim"; echo "$*"; } # usage: delim=... join elems...
|
|
83 |
join() { local IFS="$delim"; echo "$*"; } # usage: delim=... join elems... |
|
84 | 84 |
|
85 |
reverse () # usage: array=($(reverse args...))
|
|
85 |
reverse() # usage: array=($(reverse args...)) |
|
86 | 86 |
{ |
87 | 87 |
local i |
88 | 88 |
for (( i=$#; i >= 1; i-- )); do printf '%q ' "${!i}"; done |
... | ... | |
91 | 91 |
|
92 | 92 |
#### paths |
93 | 93 |
|
94 |
canon_rel_path ()
|
|
94 |
canon_rel_path() |
|
95 | 95 |
{ |
96 | 96 |
local path="$1" |
97 | 97 |
path="$(realpath "$path")" # canonicalize |
... | ... | |
112 | 112 |
#### verbose output |
113 | 113 |
|
114 | 114 |
# usage: (stdout2stderr; cmd...) || return |
115 |
# `|| return` needed on Mac because of bug where -e doesn't apply to ()
|
|
116 |
stdout2stderr () { exec >&2; }
|
|
115 |
# `|| return` needed on Mac because of bug where -e doesn't apply to() |
|
116 |
stdout2stderr() { exec >&2; } |
|
117 | 117 |
|
118 | 118 |
# set verbosity |
119 | 119 |
if isset verbose; then : "${verbosity:=$(bool2int "$verbose")}"; fi |
... | ... | |
122 | 122 |
declare -i verbosity # ensure integer |
123 | 123 |
export verbosity # propagate the verbosity to invoked commands |
124 | 124 |
|
125 |
can_log () { test "$verbosity" -gt 0; } # verbosity=0 turns off all logging
|
|
125 |
can_log() { test "$verbosity" -gt 0; } # verbosity=0 turns off all logging |
|
126 | 126 |
|
127 |
log () { if can_log; then echo "$PS4$1" >&2; fi; }
|
|
127 |
log() { if can_log; then echo "$PS4$1" >&2; fi; } |
|
128 | 128 |
|
129 | 129 |
# usage: symbol=... log_custom msg |
130 |
log_custom () { local PS4="${PS4%[^ ] }$symbol "; log "$@"; }
|
|
130 |
log_custom() { local PS4="${PS4%[^ ] }$symbol "; log "$@"; } |
|
131 | 131 |
|
132 |
log_err () { symbol=! log_custom "$@"; }
|
|
132 |
log_err() { symbol=! log_custom "$@"; } |
|
133 | 133 |
|
134 |
log_info () { symbol=? log_custom "$@"; }
|
|
134 |
log_info() { symbol=? log_custom "$@"; } |
|
135 | 135 |
|
136 | 136 |
# usage: cmd || { save_e; log_e; ...; rethrow; } |
137 |
log_e () { log_err "command exited with error $e"; }
|
|
137 |
log_e() { log_err "command exited with error $e"; } |
|
138 | 138 |
|
139 | 139 |
# usage: cmd || [type=...] die msg |
140 |
die () { save_e; "log_${type:-err}" "$1"; rethrow; }
|
|
140 |
die() { save_e; "log_${type:-err}" "$1"; rethrow; } |
|
141 | 141 |
|
142 | 142 |
: "${log_indent= }" |
143 | 143 |
|
... | ... | |
151 | 151 |
fi # load new aliases |
152 | 152 |
if self_being_included; then |
153 | 153 |
|
154 |
echo_cmd ()
|
|
154 |
echo_cmd() |
|
155 | 155 |
{ |
156 | 156 |
case "$1" in extern) shift;; esac # extern implied by the log_level |
157 | 157 |
log "$*" |
158 | 158 |
} |
159 | 159 |
|
160 |
echo_run () { cmd2rel_path; echo_cmd "$@"; "$@"; }
|
|
160 |
echo_run() { cmd2rel_path; echo_cmd "$@"; "$@"; } |
|
161 | 161 |
|
162 | 162 |
# usage: (limit_stderr; cmd...) || return |
163 |
# `|| return` needed on Mac because of bug where -e doesn't apply to ()
|
|
164 |
limit_stderr () { inc_log_level; if ! can_log; then exec 2>/dev/null; fi; }
|
|
163 |
# `|| return` needed on Mac because of bug where -e doesn't apply to() |
|
164 |
limit_stderr() { inc_log_level; if ! can_log; then exec 2>/dev/null; fi; } |
|
165 | 165 |
|
166 |
limit_stderr_cmd () # usage: [stdout2stderr=1] limit_stderr_cmd cmd...
|
|
166 |
limit_stderr_cmd() # usage: [stdout2stderr=1] limit_stderr_cmd cmd... |
|
167 | 167 |
{ |
168 | 168 |
case "$1" in echo_run) shift; cmd2rel_path; echo_cmd "$@";; esac |
169 | 169 |
(limit_stderr |
... | ... | |
179 | 179 |
# echo all external commands |
180 | 180 |
alias extern="echo_run extern " # last space alias-expands next word |
181 | 181 |
|
182 |
alias self='extern "$FUNCNAME"' # usage: wrapper () { self ...; }
|
|
182 |
alias self='extern "$FUNCNAME"' # usage: wrapper() { self ...; } |
|
183 | 183 |
|
184 | 184 |
# commands that are always external |
185 | 185 |
for cmd in env; do alias "$cmd=extern $cmd"; done; unset cmd |
186 | 186 |
|
187 |
function echo_func ()
|
|
187 |
function echo_func() |
|
188 | 188 |
{ |
189 | 189 |
inc_log_level |
190 | 190 |
local script="$(canon_rel_path "${BASH_SOURCE[1]}")" |
... | ... | |
197 | 197 |
fi # load new aliases |
198 | 198 |
if self_being_included; then |
199 | 199 |
|
200 |
echo_stdin () # usage: input|echo_stdin|cmd
|
|
200 |
echo_stdin() # usage: input|echo_stdin|cmd |
|
201 | 201 |
{ |
202 | 202 |
inc_log_level |
203 | 203 |
if can_log; then |
... | ... | |
211 | 211 |
|
212 | 212 |
alias echo_stdout='echo_stdin' # usage: cmd|echo_stdout |
213 | 213 |
|
214 |
echo_vars () # usage: echo_vars var...
|
|
214 |
echo_vars() # usage: echo_vars var... |
|
215 | 215 |
{ |
216 | 216 |
inc_log_level; inc_log_level |
217 | 217 |
if can_log; then |
... | ... | |
220 | 220 |
fi |
221 | 221 |
} |
222 | 222 |
|
223 |
echo_export () { builtin export "$@"; echo_vars "$@"; }
|
|
223 |
echo_export() { builtin export "$@"; echo_vars "$@"; } |
|
224 | 224 |
|
225 | 225 |
if test "$verbosity" -ge 2; then |
226 | 226 |
alias export="echo_export" # automatically echo env vars when they are set |
227 | 227 |
fi |
228 | 228 |
|
229 |
usage () { echo "Usage: $1" >&2; (exit 2); }
|
|
229 |
usage() { echo "Usage: $1" >&2; (exit 2); } |
|
230 | 230 |
|
231 | 231 |
fi # load new aliases |
232 | 232 |
if self_being_included; then |
... | ... | |
236 | 236 |
|
237 | 237 |
sed_ere_flag="$(test "$(uname)" = Darwin && echo E || echo r)" |
238 | 238 |
|
239 |
sed () { self -"$sed_ere_flag" "$@";}
|
|
239 |
sed() { self -"$sed_ere_flag" "$@";} |
|
240 | 240 |
|
241 | 241 |
|
242 | 242 |
#### vars |
243 | 243 |
|
244 |
set_var () { eval "$1"'="$2"'; }
|
|
244 |
set_var() { eval "$1"'="$2"'; } |
|
245 | 245 |
|
246 |
set_inv () { set_var no_"$1" "$(test "${!1}" || echo 1)"; }
|
|
246 |
set_inv() { set_var no_"$1" "$(test "${!1}" || echo 1)"; } |
|
247 | 247 |
|
248 | 248 |
# usage: local var=...; local_inv |
249 | 249 |
alias local_inv='declare "no_$var=$(test "${!var}" || echo 1)"' |
... | ... | |
262 | 262 |
|
263 | 263 |
#### functions |
264 | 264 |
|
265 |
func_exists () { declare -f "$1" >/dev/null; }
|
|
265 |
func_exists() { declare -f "$1" >/dev/null; } |
|
266 | 266 |
|
267 |
copy_func () # usage: from=... to=... copy_func
|
|
267 |
copy_func() # usage: from=... to=... copy_func |
|
268 | 268 |
# $to must not exist. to get around the no-clobber restriction, use `unset -f`. |
269 | 269 |
{ |
270 | 270 |
: "${from:?}" "${to:?}" |
... | ... | |
274 | 274 |
eval "$to${from_def#$from}" |
275 | 275 |
} |
276 | 276 |
|
277 |
func_override () # usage: func_override old_name__suffix
|
|
277 |
func_override() # usage: func_override old_name__suffix |
|
278 | 278 |
{ from="${1%%__*}" to="$1" copy_func; } |
279 | 279 |
|
280 | 280 |
|
... | ... | |
283 | 283 |
top_script="$0" # outermost script |
284 | 284 |
top_dir="$(dirname "$top_script")" |
285 | 285 |
|
286 |
require_exists () # usage: require_exists file || return 0
|
|
286 |
require_exists() # usage: require_exists file || return 0 |
|
287 | 287 |
{ test ! -e "$1" || type=info die "file "$1" already exists, skipping"; } |
288 | 288 |
|
289 | 289 |
# auto-removes a command's output file on error (like make's .DELETE_ON_ERROR) |
290 |
function to_file () # usage: stdout=... [if_not_exists=1] to_file cmd...
|
|
290 |
function to_file() # usage: stdout=... [if_not_exists=1] to_file cmd... |
|
291 | 291 |
{ |
292 | 292 |
echo_func |
293 | 293 |
: "${stdout?}"; echo_vars stdout |
... | ... | |
296 | 296 |
} |
297 | 297 |
alias to_file='to_file ' # last space alias-expands next word |
298 | 298 |
|
299 |
run_args_cmd () # runs the command line args command
|
|
299 |
run_args_cmd() # runs the command line args command |
|
300 | 300 |
{ |
301 | 301 |
test $? -eq 0 || return |
302 | 302 |
eval set -- "$(reverse "${BASH_ARGV[@]}")" |
... | ... | |
304 | 304 |
echo_cmd "$(canon_rel_path "$0")" "$@"; "$@" |
305 | 305 |
} |
306 | 306 |
|
307 |
fwd () # usage: subdirs=(...); fwd "$FUNCNAME" "$@"
|
|
307 |
fwd() # usage: subdirs=(...); fwd "$FUNCNAME" "$@" |
|
308 | 308 |
{ |
309 | 309 |
echo_func |
310 | 310 |
: "${subdirs?}" |
... | ... | |
317 | 317 |
|
318 | 318 |
#### URLs |
319 | 319 |
|
320 |
localize_url () { test _"$1" = _"$(hostname -f)" || echo "$1"; }
|
|
320 |
localize_url() { test _"$1" = _"$(hostname -f)" || echo "$1"; } |
|
321 | 321 |
|
322 | 322 |
fi |
Also available in: Unified diff
*{.sh,run}: removed extra space between function name and (), which is apparently not needed even though `help function` includes it. this greatly improves readability, including when function names are pasted into commit messages!