2023-04-16 10:04:24 +02:00
|
|
|
# Collapsing Functions
|
|
|
|
|
|
|
|
![](keywords>bash shell scripting example function collapse)
|
|
|
|
|
|
|
|
## What is a "Collapsing Function"?
|
|
|
|
|
|
|
|
A collapsing function is a function whose behavior changes depending
|
|
|
|
upon the circumstances under which it's run. Function collapsing is
|
|
|
|
useful when you find yourself repeatedly checking a variable whose value
|
|
|
|
never changes.
|
|
|
|
|
|
|
|
## How do I make a function collapse?
|
|
|
|
|
|
|
|
Function collapsing requires some static feature in the environment. A
|
|
|
|
common example is a script that gives the user the option of having
|
|
|
|
"verbose" output.
|
|
|
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
[[ $1 = -v || $1 = --verbose ]] && verbose=1
|
|
|
|
|
|
|
|
chatter() {
|
|
|
|
if [[ $verbose ]]; then
|
|
|
|
chatter() {
|
2023-04-24 13:27:29 +02:00
|
|
|
echo "$@"
|
2023-04-16 10:04:24 +02:00
|
|
|
}
|
2023-04-24 13:27:29 +02:00
|
|
|
chatter "$@"
|
2023-04-16 10:04:24 +02:00
|
|
|
else
|
|
|
|
chatter() {
|
|
|
|
:
|
|
|
|
}
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2023-04-24 13:27:29 +02:00
|
|
|
echo "Waiting for 10 seconds."
|
2023-04-16 10:04:24 +02:00
|
|
|
for i in {1..10}; do
|
2023-04-24 13:27:29 +02:00
|
|
|
chatter "$i"
|
2023-04-16 10:04:24 +02:00
|
|
|
sleep 1
|
|
|
|
done
|
|
|
|
|
|
|
|
## How does it work?
|
|
|
|
|
|
|
|
The first time you run chatter(), the function redefines itself based on
|
|
|
|
the value of verbose. Thereafter, chatter doesn't check \$verbose, it
|
|
|
|
simply is. Further calls to the function reflect its collapsed nature.
|
|
|
|
If verbose is unset, chatter will echo nothing, with no extra effort
|
|
|
|
from the developer.
|
|
|
|
|
|
|
|
## More examples
|
|
|
|
|
|
|
|
FIXME Add more examples!
|
|
|
|
|
|
|
|
# Somewhat more portable find -executable
|
|
|
|
# FIXME/UNTESTED (I don't have access to all of the different versions of find.)
|
|
|
|
# Usage: find PATH ARGS -- use find like normal, except use -executable instead of
|
|
|
|
# various versions of -perm /+ blah blah and hacks
|
|
|
|
find() {
|
|
|
|
hash find || { echo 'find not found!'; exit 1; }
|
2023-04-24 13:27:29 +02:00
|
|
|
# We can be pretty sure "$0" should be executable.
|
|
|
|
if [[ $(command find "$0" -executable 2> /dev/null) ]]; then
|
2023-04-16 10:04:24 +02:00
|
|
|
unset -f find # We can just use the command find
|
2023-04-24 13:27:29 +02:00
|
|
|
elif [[ $(command find "$0" -perm /u+x 2> /dev/null) ]]; then
|
2023-04-16 10:04:24 +02:00
|
|
|
find() {
|
|
|
|
typeset arg args
|
|
|
|
for arg do
|
2023-04-24 13:27:29 +02:00
|
|
|
[[ $arg = -executable ]] && args+=(-perm /u+x) || args+=("$arg")
|
2023-04-16 10:04:24 +02:00
|
|
|
done
|
2023-04-24 13:27:29 +02:00
|
|
|
command find "${args[@]}"
|
2023-04-16 10:04:24 +02:00
|
|
|
}
|
2023-04-24 13:27:29 +02:00
|
|
|
elif [[ $(command find "$0" -perm +u+x 2> /dev/null) ]]; then
|
2023-04-16 10:04:24 +02:00
|
|
|
find() {
|
|
|
|
typeset arg args
|
|
|
|
for arg do
|
2023-04-24 13:27:29 +02:00
|
|
|
[[ $arg = -executable ]] && args+=(-perm +u+x) || args+=("$arg")
|
2023-04-16 10:04:24 +02:00
|
|
|
done
|
2023-04-24 13:27:29 +02:00
|
|
|
command find "${args[@]}"
|
2023-04-16 10:04:24 +02:00
|
|
|
}
|
|
|
|
else # Last resort
|
|
|
|
find() {
|
|
|
|
typeset arg args
|
|
|
|
for arg do
|
2023-04-24 13:27:29 +02:00
|
|
|
[[ $arg = -executable ]] && args+=(-exec test -x {} \; -print) || args+=("$arg")
|
2023-04-16 10:04:24 +02:00
|
|
|
done
|
2023-04-24 13:27:29 +02:00
|
|
|
command find "${args[@]}"
|
2023-04-16 10:04:24 +02:00
|
|
|
}
|
|
|
|
fi
|
2023-04-24 13:27:29 +02:00
|
|
|
find "$@"
|
2023-04-16 10:04:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
\<code\> \#!/bin/bash \# Using collapsing functions to turn debug
|
|
|
|
messages on/off
|
|
|
|
|
|
|
|
\[ "--debug" = "\$1" \] && dbg=echo \|\| dbg=:
|
|
|
|
|
|
|
|
\# From now on if you use \$dbg instead of echo, you can select if
|
|
|
|
messages will be shown
|
|
|
|
|
|
|
|
\$dbg "This message will only be displayed if --debug is specified at
|
|
|
|
the command line
|