Though using find
command can be useful here, the shell itself provides options to achieve this requirement without any third party tools. The bash
shell provides an extended glob support option using which you can get the file names under recursive paths that match with the extensions you want.
The extended option is extglob
which needs to be set using the shopt
option as below. The options are enabled with the -s
support and disabled with he -u
flag. Additionally you could use couple of options more i.e. nullglob
in which an unmatched glob is swept away entirely, replaced with a set of zero words. And globstar
that allows to recurse through all the directories
shopt -s extglob nullglob globstar
Now all you need to do is form the glob expression to include the files of a certain extension which you can do as below. We use an array to populate the glob results because when quoted properly and expanded, the filenames with special characters would remain intact and not get broken due to word-splitting by the shell.
For example to list all the *.csv
files in the recursive paths
fileList=(**/*.csv)
The option **
is to recurse through the sub-folders and *.csv
is glob expansion to include any file of the extensions mentioned. Now for printing the actual files, just do
printf '%s\n' "${fileList[@]}"
Using an array and doing a proper quoted expansion is the right way when used in shell scripts, but for interactive use, you could simply use ls
with the glob expression as
ls -1 -- **/*.csv
This could very well be expanded to match multiple files i.e. file ending with multiple extension (i.e. similar to adding multiple flags in find
command). For example consider a case of needing to get all recursive image files i.e. of extensions *.gif
, *.png
and *.jpg
, all you need to is
ls -1 -- **/+(*.jpg|*.gif|*.png)
This could very well be expanded to have negate results also. With the same syntax, one could use the results of the glob to exclude files of certain type. Assume you want to exclude file names with the extensions above, you could do
excludeResults=()
excludeResults=(**/!(*.jpg|*.gif|*.png))
printf '%s\n' "${excludeResults[@]}"
The construct !()
is a negate operation to not include any of the file extensions listed inside and |
is an alternation operator just as used in the Extended Regular Expressions library to do an OR match of the globs.
Note that these extended glob support is not available in the POSIX bourne shell and its purely specific to recent versions of bash
. So if your are considering portability of the scripts running across POSIX and bash
shells, this option wouldn't be right.