For the simple task of finding all files that has a certain name using bash
, you don't need find
. The find
utility is more use useful for instances where you actually need to do operations on the found files.
The bash
shell has a special **
pattern that matches "recursively" down into subdirectories. This pattern is enabled by setting the globstar
shell option.
#!/bin/bash
shopt -s globstar dotglob nullglob
pathnames=( ./**/"$1" )
if [[ ${#pathnames[@]} -gt 0 ]]; then
printf 'Found "%s"\n' "${pathnames[@]}"
else
printf 'Found no file named "%s"\n' "$1"
fi
This would expand the pattern ./**/"$1"
, which matches all the filenames corresponding to the script's first command line argument anywhere in the current directory or below it. The resulting pathnames are stored in the array pathnames
. A test is then carried out on the length of this array, and if it contains something (the array has a length greater than zero), the elements of the array are printed out. If the array is empty, a message to this effect is printed.
The shell options dotglob
and nullglob
makes sure that shell globbing patterns matches hidden files and that the pattern is completely removed if it doesn't match anything, respectively.
Note that the script (like your attempted code) does not make any distinction between regular files, directories, symbolic links or other types of files.
Testing this script:
$ bash ~/script.sh .zshrc
Found "./.zsh/.zshrc"
Found "./skel/.zshrc"
$ cd /etc
$ bash ~/script.sh .zshrc
Found no file named ".zshrc"
Without this script, setting the failglob
and globstar
shell options in bash
would allow us to do effectively the same thing as the script directly on the command line:
$ shopt -s globstar failglob dotglob
$ echo ./**/.zsh
./.zsh
$ echo ./**/.zshrc
./.zsh/.zshrc ./skel/.zshrc
$ echo ./**/booo
bash: no match: ./**/booo
#