Reputation: 1660
The question "Test whether a glob has any matches in bash" and it's answer is quite well.
But, I want to know how to test whether a glob has only one match in bash and if it exists assign to a variable.
How can I do it?
Upvotes: 1
Views: 991
Reputation: 26481
You do not need nullglob
. With a simple test you can validate if your glob expanded to a single entry, or zero or more entries:
globexpand=( globexpression )
[[ -e "${globexpand[@]}" ]] && var="$globexpand"
This works for the following reasons:
globexpression
matches multiple files, the test with -e
will failglobexpression
matches a single file, the test with -e
will matchglobexpression
matches no file, the globexpand
will hold the globexpression
as a single entry and will fail the test with -e
. So you do not need any nullglob
or any special option. Just make sure you quote correctly here to handle filenames with special characters.
An alternative way is to make use of find
to count how many matches your glob has:
$ find . -maxdepth 1 -name 'globexpr' -printf c | wc -c
We make use of printf
so that we do not have a problem with funny filenames which might contain a newline character. Having this said, it is now straightforward:
if [[ $(find . -maxdepth 1 -name 'globexpr' -printf c | wc -c) == "1" ]]; then
# do your magic
else
# do some other stuff
fi
Upvotes: 6
Reputation: 4897
You can set nullglob
to expand globs to nothing if they match nothing. That will solve the problem the glob hanging around if there are no files matching it.
For example, here's a function which sets nullglob only for the function:
set_one () {
# Usage:
# set_one myvar "some?glob*"
# save nullglob setting (https://stackoverflow.com/a/34957289/2072269),
# disable field splitting and enable nullgob
declare nullglob=$(shopt -p nullglob) IFS=
shopt -s nullglob
# expand second argument as a glob and reset nullglob to saved setting
declare -a array=($2)
eval "$nullglob"
(( ${#array[@]} != 1 )) && return 1
# save first element of array to variable given by first argument
printf -v "$1" "%s" "$array"
}
Example:
$ ls
a b c
$ set_one foo "*"; echo $? "$foo"
1
$ set_one foo "a*"; echo $? "$foo"
0 a
$ set_one foo "[d]"; echo $? "$foo"
1 a # retains previous value
Upvotes: 2