How to pass a regex when finding a directory path in bash?
This is a surprisingly tricky thing to do nicely.
Fundamentally, -d
will only test a single argument - even if you could match filenames using a regular expression.
One way would be to flip the problem around, and test directories for a regex match instead of testing the regex match for directories. In other words, loop over all the directories in $HOME
using a simple shell glob, and test each against your regex, breaking on a match, finally testing whether the BASH_REMATCH
array is non-empty:
#!/bin/bash
for d in "$HOME"/*/; do
if [[ $d =~ (ana|mini)conda[0-9]? ]]; then
break;
fi
done
if ((${#BASH_REMATCH[@]} > 0)); then
echo "anaconda/miniconda directory is found in your $HOME"
else
echo "anaconda/miniconda is not found in your $HOME"
fi
An alternate way would be to use an extended shell glob in place of the regex, and capture any glob matches in an array. Then test if the array is non-empty:
#!/bin/bash
shopt -s extglob nullglob
dirs=( "$HOME"/@(ana|mini)conda?([0-9])/ )
if (( ${#dirs[@]} > 0 )); then
echo "anaconda/miniconda directory is found in your $HOME"
else
echo "anaconda/miniconda is not found in your $HOME"
fi
The trailing /
ensures that only directories are matched; the nullglob
prevents the shell from returning the unmatched string in the case of zero matches.
To make either recursive, set the globstar
shell option (shopt -s globstar
) and then respectively:-
(regex version):
for d in "$HOME"/**/; do
(extended glob version):
dirs=( "$HOME"/**/@(ana|mini)conda?([0-9])/ )
Indeed, as already mentioned, this is tricky. My approach is the following:
- use
find
and its regex capabilities to find the directories in question. - let
find
print anx
for each found directory - store the
x
es in a string - if the string is non-empty, then one of the directories was found.
Thus:
xString=$(find $HOME -maxdepth 1 \
-type d \
-regextype egrep \
-regex "$HOME/(ana|mini)conda[0-9]?" \
-printf 'x');
if [ -n "$xString" ]; then
echo "found one of the directories";
else
echo "no match.";
fi
Explanation:
-
find $HOME -maxdepth 1
finds everything below$HOME
but restricts the search to one level (that is: it doesn't recurse into subdirectories). -
-type d
restricts the search to onlyd
irectories -
-regextype egrep
tellsfind
what type of regular expression we deal with. This is needed because things like[0-9]?
and(…|…)
are somewhat special andfind
doesn't recognize them by default. -
-regex "$HOME/(ana|mini)conda[0-9]?"
is the actual regular expression we want to lookout for -
-printf 'x'
just prints anx
for every thing that satisfies the previous conditions.