2910

How can I recursively find all files in current and subfolders based on wildcard matching?

hyde
  • 60,639
  • 21
  • 115
  • 176
john
  • 33,520
  • 12
  • 45
  • 62

19 Answers19

4118

Use find:

find . -name "foo*"

find needs a starting point, so the . (dot) points to the current directory.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
tux21b
  • 90,183
  • 16
  • 117
  • 101
  • 33
    I know this is tagged as linux but this is worth mentioning: the path is required for on other *nix variants that aren't linux. On linux, the path is optional if you want to use dot. – IslandCow Nov 16 '13 at 00:14
  • 6
    @Seatter "foo*" tells find to look for all files that start with "foo". It is just his example. You could use "gpio*" to find all files who's names start with gpio, or just "gpio1" to find all files named gpio1. – schumacher574 Apr 02 '14 at 18:00
  • * is a wildcard - more wildcard possibilities here: http://www.tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm – Michael Apr 30 '14 at 10:29
  • 54
    note that the "foo*" is in quotes so the shell doesn't expand it before passing it to find. if you just did `find . foo*`, the `foo*` would be expanded AND THEN passed to find. – grinch May 19 '14 at 14:29
  • 4
    use -iname for case insensitive – Bharat Pahalwani Mar 20 '15 at 10:05
  • I have a file test.xml in the subdirectory of my current working directory and I have used the command find . -name "test*". It doesnt work. – Atom Nov 12 '15 at 00:46
  • 1
    For some reason it doesn't work when put in a sh script. Does it need bash or something? – Howie Feb 18 '16 at 13:54
  • 77
    Worth stressing that `" "` is very necessary for recursive searching. – WesternGun Oct 21 '16 at 11:43
  • 31
    Also useful: If you don't want to be notified about directories you don't have permission to (or other errors), you can do `find . -name "foo*" 2>/dev/null` – Jobbo Aug 15 '17 at 10:54
  • If you wish to ignore case (as in most cases when I use this) then you could do: find . -iname "foo*" – Orn Arnarson Mar 19 '18 at 18:10
  • In reponse to @IslandCow's comment: that's not true (at least not everywhere). I have to use '.' explicitly on my Fedora boxes. – Clearer Mar 29 '18 at 13:31
  • 2
    @WesternGun Can you explain why the `" "` is needed? What is "expansion" and why is that bad? – Kellen Stuart May 10 '18 at 17:49
  • 2
    @KolobCanyon you can check the man page of find, or [this link](https://linux.die.net/man/1/find) and search the word "non-bug" and then "quote", there you have more info. Also, check [this](http://linuxcommand.org/lc3_lts0080.php). Generally, `*` expansion is "iterate current dir and substitute the * with every file name". So, to avoid this, we use quotes. – WesternGun May 11 '18 at 06:44
  • @WesternGun Is that different than string interpolation? Because I thought quotes meant string interpolation in the shell – Kellen Stuart May 11 '18 at 15:11
  • 1
    @KolobCanyon something like that, but the links have more and I think expansion is broader. – WesternGun May 11 '18 at 15:31
  • This is ridiculous... what if I only want to search in the current dir?? – Yan King Yin Feb 17 '19 at 04:08
  • @yan king yin - use `ls`? – KolonUK Apr 16 '19 at 10:12
  • weirdly enough this doesn't work me. What worked for me is the answer from Paul Whipp – code_gamer May 27 '19 at 14:26
  • 1
    If I leave out the quotes, it searches only in the current directory. The genius designer of this should explain the behavior. – Yan King Yin Aug 25 '19 at 12:25
  • dot does not work for me, I have to use `find /some/path/ -iname "foo*"` – andrej Aug 17 '20 at 13:07
  • 1
    note that sometime subdirectories are sym-linked, and to traverse those you need to include -L option – KGhatak Nov 16 '21 at 10:44
  • ag -g / is better (because multi threading). – GL2014 Mar 22 '22 at 02:18
  • 1
    If you want only files **without the directories**, use [`-type f`](https://stackoverflow.com/a/42052661/9157799) – M Imam Pratama May 17 '22 at 11:34
  • It seems that this does not work when I am looking for wildcard expanding in the full path name. Say I am looking for files such that the full path matches `string1*string2*`, for example `/home/string1bla/string2.txt`, how would I do this? – Kvothe Jul 12 '22 at 22:12
  • To answer my own question above. Use the `-path` option, see https://superuser.com/a/400086/728074. – Kvothe Jul 12 '22 at 22:18
311

Piping find into grep is often more convenient; it gives you the full power of regular expressions for arbitrary wildcard matching.

For example, to find all files with case insensitive string "foo" in the filename:

find . -print | grep -i foo
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Paul Whipp
  • 16,028
  • 4
  • 42
  • 54
  • 107
    `find` also has the `-iname`, `-regex`, and `-iregex` flags for case-insensitive wildcard, regex, and case-insensitive regex matching, so piping to `grep` is unnecessary. – iobender Aug 04 '15 at 16:54
  • 9
    I don't think it is about being unnecessary, but being more convenient. – Elijah Lynn Feb 08 '17 at 16:57
  • 3
    However, piping to grep -v can allow you to use simple strings or regexes to remove entries you don't want. – door_number_three Apr 06 '17 at 03:15
  • 7
    @iobender - Sadly, I can tell you from experience that not all systems come with a `find` command that supports those options. Sometimes `grep` becomes the only option. – Mr. Llama Jul 05 '18 at 17:36
  • 1
    One important caveat here is that if you're using find on a directory that contains A LOT of files (eg; `\`) then this can be quite slow. – alfalfasprout Jul 22 '22 at 16:38
215

find will find all files that match a pattern:

find . -name "*foo"

However, if you want a picture:

tree -P "*foo"
IslandCow
  • 3,412
  • 3
  • 19
  • 24
104

fd

In case find is too slow, try the fd utility - a simple and fast alternative to find written in Rust.

Syntax:

fd PATTERN

Demo:

Homepage: https://github.com/sharkdp/fd

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kenorb
  • 155,785
  • 88
  • 678
  • 743
77
find -L . -name "foo*"

In a few cases, I have needed the -L parameter to handle symbolic directory links. By default symbolic links are ignored. In those cases it was quite confusing as I would change directory to a sub-directory and see the file matching the pattern but find would not return the filename. Using -L solves that issue. The symbolic link options for find are -P -L -H

toddcscar
  • 1,115
  • 9
  • 12
  • 6
    L switch is very helpful. Many times user do not have any idea about underlying directories, whether they are softlinked or are normal directories. So in case of doubt, it always good to use L option. At least, it has always helped me. – Ritesh Jan 03 '18 at 16:21
66

Use

find <directory_path>  -type f -name "<wildcard-match>"

In the wildcard-match you can provide the string you wish to match, e.g., *.c (for all C files).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
XYZ_Linux
  • 3,247
  • 5
  • 31
  • 34
  • 4
    Your answer is the first most correct here as it only searches files as specified. The others not specifying type will return directories. – wilsotc Nov 23 '17 at 01:15
  • 1
    if you wish to search for a directory "-type f" could be changed to "-type d " – XYZ_Linux Sep 11 '19 at 07:02
  • By default, `find` detect symbolic **file** links (but not the ones in symbolic **directory** links). `-type f` will cause `find` to not detect symbolic **file** links. If you also want to include symlinks that point to a file, use [`-L`](https://stackoverflow.com/a/41646309/9157799): `find -L -type f`. Don't use `-type f,l` since it will also include symbolic **directory** links. – M Imam Pratama May 17 '22 at 11:54
60

If your shell supports a new globbing option (can be enabled by: shopt -s globstar), you can use:

echo **/*foo*

to find any files or folders recursively. This is supported by Bash 4, zsh and similar shells.


Personally I've got this shell function defined:

f() { find . -name "*$1*"; }

Note: Above line can be pasted directly to shell or added into your user's ~/.bashrc file.

Then I can look for any files by typing:

f some_name

Alternatively you can use a fd utility with a simple syntax, e.g. fd pattern.

kenorb
  • 155,785
  • 88
  • 678
  • 743
42

Use

find path/to/dir -name "*.ext1" -o -name "*.ext2"

Explanation

  1. The first parameter is the directory you want to search.
  2. By default find does recursion.
  3. The -o stands for -or. So above means search for this wildcard OR this one. If you have only one pattern then no need for -o.
  4. The quotes around the wildcard pattern are required.
Shital Shah
  • 63,284
  • 17
  • 238
  • 185
18

You can use:

find . -type f  -name 'text_for_search'

If you want use a regular expression, use -iname:

find . -type f  -iname 'text_for_search'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user8848899
  • 181
  • 1
  • 3
17

The default way to search for files recursively, and available in most cases is

find . -name "filepattern"

It starts recursively traversing for filename or pattern from within the current directory where you are positioned. With the find command, you can use wildcards, and various switches. To see the full list of options, type

man find

Or if man pages aren't available at your system:

find --help

However, there are more modern and faster tools than find, which are traversing your whole filesystem and indexing your files. One such common tool is locate or slocate/mlocate. You should check the manual of your OS on how to install it, and once it's installed, it needs to initiate the database. If the install script doesn't do it for you, it can be done manually by typing

sudo updatedb

And, to use it to look for some particular file, type:

locate filename

Or, to look for a filename or pattern from within the current directory, you can type:

pwd | xargs -n 1 -I {} locate "filepattern"

It will look through its database of files and quickly print out path names that match the pattern that you have typed. To see the full list of locate's options, type: locate --help or man locate

Additionally, you can configure locate to update its database on scheduled times via a cron job, so a sample cron which updates the database at 1 AM would look like:

0 1 * * * updatedb

These cron jobs need to be configured by root, since updatedb needs root privileges to traverse the whole filesystem.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aleksandar Pavić
  • 3,143
  • 1
  • 34
  • 36
14

For file search

find / -xdev -name settings.xml → the whole computer
find ./ -xdev -name settings.xml → the current directory and its subdirectories

For files with an extension type:

find . -type f -name "*.iso"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alberto
  • 195
  • 1
  • 2
  • 9
14

I am surprised to see that locate is not used heavily when we are to go recursively.

I would first do a locate "$PWD" to get the list of files in the current folder of interest, and then run greps on them as I please.

locate "$PWD" | grep -P <pattern>

Of course, this is assuming that the updatedb is done and the index is updated periodically. This is much faster way to find files than to run a find and asking it go down the tree. Mentioning this for completeness. Nothing against using find, if the tree is not very heavy.

melchi
  • 627
  • 6
  • 10
13

The following command will list down all the files having the exact name "pattern" (for example) in the current and its sub folders.

find ./ -name "pattern"

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Anshul Singhal
  • 1,983
  • 20
  • 25
  • 2
    Downvote. This repeats a [2017 answer](https://stackoverflow.com/a/44279931/11154841). – questionto42 Aug 31 '21 at 11:03
  • 1
    @Brian New answers are expected to provide some new info or an alternative solution, repeating what already has been said is not useful. Just like [when asking a question](/help/how-to-ask), before writing an answer you should search first to make sure your answer will add something useful. Especially when there are lots of other answers, as in such case the possibility of this approaches 0. It's not hard at all, only a single Ctrl+F away. – EvgenKo423 May 28 '22 at 07:56
  • Yes your are right. I agree now that i thought more about it. – Brian Wiley May 28 '22 at 09:20
9

The below command helps to search for any files

  1. Irrespective of case
  2. Result excluding folders without permission
  3. Searching from the root or from the path you like. Change / with the path you prefer.

Syntax:

find <FromDirectory> -iname '<FileName wild char allowed>'   2>&1 | grep -v "Permission denied"

Example

find / -iname 'C*.xml' 2>&1 | grep -v "Permission denied"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MukeshKoshyM
  • 514
  • 1
  • 8
  • 16
  • 5
    why on earth do you use grep for that? Just redirect stderr to null `find / -iname '*C*.xml' 2>/dev/null` – phuclv Mar 23 '19 at 05:51
9

This will search all the related files in current and sub directories, calculating their line count separately as well as totally:

find . -name "*.wanted" | xargs wc -l
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jay Yang
  • 384
  • 5
  • 6
8

If you want to search special files with a wildcard, you can use the following code:

find . -type f -name "*.conf"

Suppose, you want to search every .conf files from here:

. means search started from here (current place)
-type means type of search item that here is file (f).
-name means you want to search files with *.conf names.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Saman Bayat
  • 256
  • 2
  • 11
  • 2
    Downvote. These should have been comments under or edits of the [2011 accepted answer](https://stackoverflow.com/a/5905066/11154841). – questionto42 Aug 31 '21 at 11:16
8

Try with the fd command if installed. Install instructions.

Find all files that start with 'name':

fd "name*"

This command ignores all .hidden and .gitignoreed files.

To include .gitignoreed files, add the -I option as below:

fd -I "name*"

To include hidden files, add the -H option as below:

fd -H "name*"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Robert Ranjan
  • 1,538
  • 3
  • 19
  • 17
0

You can also use ripgrep.

Example:

Search all the filenames contain substring psql,

rg --files | rg psql
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jian
  • 4,119
  • 1
  • 17
  • 32
-6

With Python>3.5, using glob, . pointing to your current folder and looking for .txt files:

 python -c "import glob;[print(x) for x in glob.glob('./**/*txt', recursive=True)]"

For older versions of Python, you can install glob2

E_net4
  • 27,810
  • 13
  • 101
  • 139
Katu
  • 1,296
  • 1
  • 24
  • 38
  • 3
    _Can someone explain the downvotes? If there is something wrong with my answer, I would like to know what it is._ – This question asks a _native_ solution for Linux shells and you provide an answer in Python. So your answer is off-topic here. – EvgenKo423 Nov 12 '21 at 09:34
  • I don't understand part of your comment @EvgenKo423, since this answer was answered by Katu and not by you. – Valerio Bozz Nov 16 '21 at 15:57
  • 1
    @ValerioBozz Look at the [revision history](https://stackoverflow.com/posts/66128889/revisions). I had quoted their question and answered it. – EvgenKo423 Nov 17 '21 at 14:38
  • 1
    _I have seen plenty of questions about `sed` with accepted answers that use `awk` and similar. [...] It feels like this is getting downvoted by people following the trend instead of thinking about it._ – But both `sed` and `awk` are command line tools, while the Python is a full-featured programming language. Downvoting answers costs rep which discourages doing so for no reason, but if you still think it's a voting fraud, have a read of [this post](https://meta.stackexchange.com/a/126857/578924). P.S.: Please use comments or [chat] for discussions, they don't belong in answers. – EvgenKo423 Jan 19 '22 at 07:50