Skip to content

Commit 4a4631e

Browse files
Kerin Millarthesamesam
Kerin Millar
authored andcommitted
isolated-functions.sh: add the contains_word() function
Add the contains_word() function, whose purpose is to determine whether a word is contained by another string comprising zero-or-more whitespace-separated words. This is a use case for which the has() function tends to be rampantly misappropriated. Below are some examples. # Slow; sensitive to the value of IFS; can incur pathname expansion. has xattr ${FEATURES} # Ditto. has nostrip ${FEATURES} ${PORTAGE_RESTRICT} # Ditto, only with $1 also being treated unsafely. has $1 {INHERITED} Indeed, has() is sometimes used in situations where there is simply no call for it whatsoever. Below are some prior examples for posterity. # Slow. Fails to quote the expansion and is a silly way of writing: # [[ ${suffix} == @(Z|gz|bz2) ]] has ${suffix} Z gz bz2 # A silly way of writing: [[ ${EAPI} == [23] ]] has "${EAPI:-0}" 2 3 # A silly way of writing: [[ ${EBUILD_PHASE} != clean?(rm) ]] ! has "${EBUILD_PHASE}" clean cleanrm The new function is faster in all cases, with the observable performance delta increasing for matches made against words further towards the right of the haystack string (owing to for loops being very slow in bash). The following benchmarks entailed searching 33 words within FEATURES for "keepwork" - the middle word - 10,000 times. has() real 0m2.027s user 0m2.027s sys 0m0.000s contains_word() real 0m0.905s user 0m0.905s sys 0m0.000s Further, going about it in this way renders xtrace output less noisy. Acknowledgement is due to Jan Chren (a.k.a. rindeal), who independently issued a conceptually similar GitHub pull request (#458) in September 2019. I was initially unaware of this until Sam James pointed it out. Link: #458 Signed-off-by: Kerin Millar <[email protected]> Signed-off-by: Sam James <[email protected]>
1 parent 154c7dc commit 4a4631e

File tree

1 file changed

+12
-0
lines changed

1 file changed

+12
-0
lines changed

bin/isolated-functions.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,9 @@ hasv() {
537537
return 1
538538
}
539539

540+
# Determines whether the first parameter is stringwise equal to any of the
541+
# following parameters. Do NOT use this function for checking whether a word is
542+
# contained by another string. For that, use contains_word() instead.
540543
has() {
541544
local needle=$1
542545
shift
@@ -676,4 +679,13 @@ debug-print-section() {
676679
debug-print "now in section ${*}"
677680
}
678681

682+
# Considers the first parameter as a word and the second parameter as a string
683+
# comprising zero or more whitespace-separated words before determining whether
684+
# said word can be matched against any of them. It addresses a use case for
685+
# which the has() function is commonly misappropriated, with maximal efficiency.
686+
contains_word() {
687+
local IFS
688+
[[ $1 == +([![:space:]]) && " ${*:2} " == *[[:space:]]"$1"[[:space:]]* ]]
689+
}
690+
679691
true

0 commit comments

Comments
 (0)