What's an idiomatic way to test if a string contains a substring in a Posix Shell?
Basically this, but Posix:
[[ ${my_haystack} == *${my_needle}* ]]
I'm looking for the equivalent of this, but that works in a Posix / Almquist / dash / ash shell:
#!/bin/bash
set -e
set -u
find_needle() {
my_haystack="${1}"
my_needle="${2}"
if [[ ${my_haystack} == *${my_needle}* ]]; then
echo "'${my_haystack}' contains '${my_needle}'"
else
echo "'${my_haystack}' does NOT contain '${my_needle}'"
fi
}
find_needle "${1:-"haystack"}" "${2:-"a"}"
(that doesn't work in sh
)
My ideal solution would be one that doesn't require the use of a subshell or pipe, and that doesn't exit on failure in strict mode.
This works, but I'm wondering if there's another way to test a substring without echoing and piping to grep.
#!/bin/sh
set -e
set -u
find_needle() {
my_haystack="${1}"
my_needle="${2}"
if echo "${my_haystack}" | grep -q "${my_needle}"; then
echo "'${my_haystack}' contains '${my_needle}'"
else
echo "'${my_haystack}' does NOT contain '${my_needle}'"
fi
}
find_needle "${1:-"haystack"}" "${2:-"a"}"
Or maybe this is the most idiomatic way?
case
As @dave_thompson_085 points out [1], you can use case
:
case $haystack in
*$needle*)
return 0
;;
*)
return 1
;;
esac
See also:
#!/bin/sh
set -e
set -u
test_substring() {
haystack="${1}"
needle="${2}"
case $haystack in
*$needle*)
return 0
;;
*)
return 1
;;
esac
}
find_needle() {
my_haystack="${1}"
my_needle="${2}"
if test_substring "${my_haystack}" "${my_needle}"; then
echo "'${my_haystack}' contains '${my_needle}'"
else
echo "'${my_haystack}' does NOT contain '${my_needle}'"
fi
}
find_needle haystack a
find_needle haystack x
Output:
'haystack' contains 'a'
'haystack' does NOT contain 'x'