func
Functions that are useful for writing utility functions that use getopts or similar and want to print simple error message in the terminal.
The idea is to print usable message to the user and spent no time creating it.
How it works:
- Bash function has a help message stored in the comment preceeding the function.
- We can extract the comment by finding the function definition and parsing the file.
- The comment becomes the help message.
- Usage is extracted from comment by parsing lines that match the format of https://github.com/Kamilcuk/mkdocstrings-sh .
# @option -o <var> description- describes a short option taking an argument# @option -o description- describes a short option not taking an argument# @arg name description- describes an argument called name.# @usage description- allows to specify custom usage line
How to use:
- Use
L_func_helpto print the help message. - Use
L_func_error "error message" || return 2to print the error message with usage of the function, and then return from your function. - Use
L_func_assert "not enough arguments" test "$#" -lt 1 || return 2to print the error message with usage of the function and then return from your function when the commandtest "$#" -lt 1fails, which effectively checks if there are enough arguments.
func
¶
Function for writing function programs.
L_func_comment
¶
Extract the comment above the function.
By default, get the comment of the calling function.
Example
# some unrelated comment followed by an empty line
# some comment
somefunc() {
L_func_comment
}
somefunc # outputs '# some comment'
L_func_comment -f somefunc
Options:
-
-v <var>Assign result to this variable. -
-f <funcname>Print the comment of given function instead of the calling function. -
-s <int>Consider the calling function this many stackframes above. Default: 0 -
-bUse Bash, do not use sed. For testing. -
-hPrint this help and return 0.
Return: 0 if extracted an non-empty comment above the function definition.
L_func_help
¶
Print function comment as usage message.
:
# @option -t this is an option
# @option -g <arg> this is an option with an argument
# @option -h Print this help and return 0.
# @arg arg This is an argument
utility() {
local OPTIND OPTARG OPTERR opt t g
while getopts tg:h opt; do
case "$opt" in
t) t=1 ;;
g) g=$OPTARG ;;
h) L_func_help; return 0 ;;
*) L_func_usage; return 2 ;;
esac
done
shift "$((OPTARG-1))"
L_func_assert "one positional argument required" test "$#" -eq 1 || return 2
#
: utility logic
}
utility -h # prints the comment above the function
utility -invalid # prints 'Usage: utility [-th] [-g arg] arg'
Argument:
[int]
How many stack frames up.
Return: 0
See:
L_func_usage
¶
Print funtion usage to stderr.
Argument:
[$1]
How many stack frames up.
L_func_error
¶
Print function error to stderr.
Arguments:
-
[$1]Message. -
[$2]How many stack frames up.
See: L_func_help for example
L_func_usage_error
¶
Print function error with usage.
Arguments:
-
[$1]Message. -
[$2]How many stack frames up.
See: L_func_help for example
L_func_assert
¶
Assert that the command exits with 0.
If it does not, call L_func_error and return 2. If the message starts with -[0-9]+, the number is used as the number of stackframes up the message is about.
Example
utility() {
local num="$1"
L_func_assert "not a number: $num" L_is_integer "$num" || return 2
}
Arguments:
-
$1Message to print, may be empty. -
$@Arguments to test.
Return: 2 if the expression failed.
L_func_log
¶
Print a line prefixed by the calling function name.
Argument:
$@
line to print
L_function_copy
¶
Make a copy of a function.
Currently there is no sanitization done in the function. The second argument allows for execution under eval.
Arguments:
-
$1existing function -
$2new function name
L_function_modify
¶
Add a script on the top or the end of a function.
Arguments:
-
$1The function to modify -
$2Script to put in front of the function body. -
$3Script to put on the end of the function body.
L_decorate
¶
Apply a decorator on a function.
The next call on a function will call the decorator with arguments followed by function name with arguments.
Example
func() { echo something; }
print_and_call() {
echo "CALLING: $@" >&2
"$@"
}
func # outputs something
func # outputs something
L_decorate print_and_call func
func # outputs "CALLING func" and then "something"
func # outputs "CALLING func" and then "something"
Example
func() { L_print_traceback; }
L_decorate L_setx func
L_decorate time func
L_decorate L_setx time func
func arg # calls: [L_setx time func arg]
# which calls [time func arg]
# which calls L_setx func arg
Arguments:
-
$@Decorator to apply with arguments. -
$#-1Function.
L_time
¶
Measure time with the command, but include the command in the time message output and use %6l format.
Argument:
$@
command to measure.
L_duration_to_usec
¶
Parse 1w1d1h2m2s into number of microseconds.
Option:
-v <var>
Argument:
$1
Duration string.
See: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#configuration-file
L_duration_to_usec_v
¶
L_cache
¶
Cache the execution of a command.
The command execution is cached in _L_CACHE global variable or in file when -f option is present. The second execution of the command will result in a cached execution. On cached execution the exit status of the command will be extracted from the cache.
Example
L_cache -T 10m -O output -f /tmp/cache.L_cache curl -sS https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html
myfunc() {
var=$(( 1 + 2 ))
}
L_decorate L_cache -v var -k myfunc myfunc
myfunc
myfunc
Options:
-
-oCache the stdout of the command.
It will run the command in a process substitution.
-
-O <var>Cache the stdout of the command and store it in variable instead of printing.
It will run the command in a process substitution.
-
-s <var>Add this variable to the cache. All cache variables will be restored on cached execution. -
-f <file>Use the file as cache.
The file has a header with version number. The file stores internal cache state from declare -p _L_cache variable. The file content is eval-ed upon loading.
-
-rInstead of executing, remove the cache entry associated with the command. -
-lInstead of executing, only list the entires in the cache. -
-T <ttl>Set time to live in duration string. Default: infinity. -
-L <01>Lock the file with flock. Default: use flock if available. -
-k <key>Use this key to index the cache. Default: %q quoted command with argumnets. -
-hPrint this help and return 0.
Arguments:
-
$1Command to execute. -
$@Arguments.
Sets variable:
_L_CACHE
Uses environment variable:
_L_CACHE
Shellcheck disable= SC2094
Return:
222 on internal error
otherwise returns the exit status of the cached command.
L_handle_v_scalar
¶
Wrapper function for handling -v arguments to other functions.
It calls a function called <caller>_v with arguments, but without -v <var>.
The function <caller>_v should set the variable nameref L_v to the returned value.
When the caller function is called without -v, the value of L_v is printed to stdout with a newline.
Otherwise, the value is a nameref to user requested variable and nothing is printed.
The fucntion L_handle_v_scalar handles only scalar value of L_v or 0-th index of L_v array.
To assign an array, prefer L_handle_v_array.
:
L_hello() { L_handle_v_arr "$@"; }
L_hello_v() { L_v="hello world"; }
L_hello # outputs 'hello world'
L_hello -v var # assigns var="hello world"
Option:
-v <var>
Store the output in variable instead of printing it.
Argument:
$@
arbitrary function arguments
Shellcheck disable= SC2317
Exit:
Whatever exitcode does the <caller>_v funtion exits with.
See: L_handle_v_array
L_handle_v_array
¶
Version of L_handle_v_scalar for arrays.
The options and arguments and exitcode is the same as L_handle_v_scalar.
This additionally supports assignment to arrays. This is not possible with L_handle_v_scalar.
The function L_handle_v_scalar is slightly faster and uses printf -v to assign the result.
On newer Bash, printf -v can assign to array and associative arrays variable indexes.
In constract, L_handle_v_array has to first assert if the string is a valid variable name.
Only then it uses eval with an array assignment syntax to assign the result to the user requsted variable.
Currently array indexes are not preserved. This could be worked on in the future when needed.
:
L_hello() { L_handle_v_arr "$@"; }
L_hello_v() { L_v=(hello world); }
L_hello # outputs two lines 'hello' and 'world'
L_hello -v var # assigns var=(hello world)
Shellcheck disable= SC2317
See: L_handle_v_scalar.