To print the filenames in Folder that contain b and not a, in zsh and its ~ (except / and-not) glob operator:
#! /bin/zsh -
set -o extendedglob
print -rC1 -- Folder/(*b*~*a*)(N:t)
(remove the N (for nullglob, if you'd rather want an error be reported where there's no matching file).
In ksh93 (the shell that introduced that [[...]] operator (which is not part of the standard sh syntax) and its & (and) and !(...) (not) operators:
#! /bin/ksh93 -
(
CDPATH= cd Folder &&
set -- ~(N)@(*b*&!(*a*)) &&
(($# > 0)) &&
printf '%s\n' "$@"
)
With the bash shell (which like zsh has also copied ksh's [[...]] operator), using extglob to support ksh88 glob operators and nullglob to get the effect of zsh's N glob qualifier or ksh93's ~(N) glob operator and some double negation with | (or) to achieve and:
#! /bin/bash -
(
shopt -s extglob nullglob
cd ./Folder &&
set -- !(!(*b*)|*a*) &&
(($# > 0)) &&
printf '%s\n' "$@"
)
In standard sh syntax:
#! /bin/sh -
(
CDPATH= cd Folder || exit
set -- [*]b[*] *b*
[ "$1/$2" = '[*]b[*]/*b*' ] && exit # detect the case where the pattern
# expands to itself because there's
# no match as there's no nullglob
# equivalent in sh
shift
for i do
case $i in
(*a*) ;;
(*) set -- "$@" "$i"
esac
shift
done
[ "$#" -gt 0 ] && printf '%s\n' "$@"
)
Note that the solutions that use cd won't work if you have read access to Folder but not search access to it.
More generally, to answer the general question of how to check if a string contains another one in sh, best is with the case construct which is how you do pattern matching in sh. You could even use a helper function:
contains()
case "$1" in
(*"$2"*) true;;
(*) false;;
esac
To use as if:
if contains foobar o; then
echo foobar contains o
fi
if ! contains foobar z; then
echo foobar does not contain o
fi
if
contains "$file" b &&
! contains "$file" a
then
printf '%s\n' "$file contains b and not a "
fi