Temporary Env Variable as Argument with Unset
Pattern for setting input values of functions through temporary environment variables.
# EXAMPLE
#
# This is our public facing function.
ai.review(){
# Here we set requires configuration of the private implementation function,
# through and environment variable.
#
# Note we make ARG_ENV__TEMPLATE_FILE scoped to _ai_review function by placing
# it on the same line as _ai_review (by means of line continuation operator).
#
# "The environment for any simple command or function may be augmented temporarily by prefixing it
# with parameter assignments, as described above in PARAMETERS. These assignment statements affect
# only the environment seen by that command." - bash manpage
ARG_ENV__TEMPLATE_FILE="${TEMPLATES:?}/ai/review_request.md" \
_ai_review
}
_ai_review(){
local template_file="${ARG_ENV__TEMPLATE_FILE:?}"
# Unset the ARG_ENV__TEMPLATE_FILE so that if syntax of setting environment variable not just
# for this function is used. We make sure to unset it.
unset ARG_ENV__TEMPLATE_FILE
#...
}
Alternatives:
- Positional arguments (this should be the default).
- Work well but if there are existing positionals with defaults its not so easy to add another argument.
- Named arguments (
--template-file
syntax), require more complex code to parse.
CONs
Potential environment pollution
The main con of this approach is the potential environment pollution if someone uses functions without scoping the environment variables to the function we are calling, without providing all required functions.
foo() {
local arg1="${ENV_ARG__1:?arg1}"
unset ENV_ARG__1
local arg2="${ENV_ARG__2:?arg1}"
unset ENV_ARG__2
# ...
}
main() {
# To pollute environment a bit there are 2 conditions that are crated by the caller
#
# ## 1) Caller does not make variable scoped to calling function
# We set the ENV_ARG__1 as environment variable, without making it a temporary
# environment variable that is applicable only to foo by putting them on the same line.
# like:
# ENV_ARG__1="arg1-val" foo
#
# # \ - line continuation character
# ENV_ARG__1="arg1-val" \
# foo
#
# ## 2) Caller forgets to set all required ENV_ARG variables.
# Even if condition one is met, since we use 'unset' within 'foo' if all required
# variables are provided foo will clean up the environment. However, if only
# part of required variables are provided. We can run into situation where 'foo'
# wil abort prior to cleaning the environment.
#
# In this example 'foo' will fail on 'ENV_ARG__1' check and will NOT be able
# to clean up ENV_ARG__2
ENV_ARG__2="arg1-val"
foo
}