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