I have a script with a user-entered name, and want to determine whether any directories exist starting with that name.
This code looks like:
runTest() { if test -d "$name"*; then echo "Directories starting with $name already exist" fi }
It works fine if there is only one such directory:
name=foobar rm -rf foobar* mkdir foobar1 runTest # now the code will work
…but it doesn’t work if there are multiple matches:
name=foobar rm -rf foobar* mkdir foobar1 foobar2 runTest # now the code will emit an error: "test: too many arguments"
How can I make this work with any number of directories, without assuming that one of the matches will always include a specific number (like 1
)?
Advertisement
Answer
As an example of a working (bash-only — not /bin/sh
compatible) alternative, consider:
if dirs=( "$name"*/ ) && [[ -d ${dirs[0]} ]]; then echo "Directories starting with $name already exist" fi
- An array assignment works with any number of matches
- …but the first entry in the array will be a valid directory only if the glob successfully expanded (and the trailing
/
in the glob expression prevents it from expanding to anything except directories, so if the result has any directories at all, you know that all elements it expanded to are directories).
If you need something that works for /bin/sh
as well, consider the following function:
directoriesExist() { [ -d "$1" ]; } if directoriesExist "$name"*/; then echo "Directories starting with $name already exist" fi
This works because the list of matches expands onto the function’s argument list, effectively serving as an alternative to an array.
Because [
is a shell builtin, these globbing-based approaches have much lower constant-factor costs than approaches depending on external tools, which will make them considerably faster overall (except for some corner cases, such as directories so large that it’s preferable to stop after the first match is found; where find . -name "$name*" -print -quit
may be useful).