198

grep is used to search within a file to see if any line matches a given regular expression. However, I have this situation - I want to write a regular expression that will match the filename itself (and not the contents of the file). I will run this from the system's root directory, to find all those files that match the regular expression.

For example, if I want to find all Visual Basic form files that start with an "f" and end with .frm, I'll use the regular expression -

   "f[[:alnum:]]*\.frm"

Can grep do this? If not, is there a utility that would let me do this?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CodeBlue
  • 14,631
  • 33
  • 94
  • 132
  • 1
    The must be a lot of duplicates from the first nearly four years. – Peter Mortensen Apr 24 '21 at 10:34
  • ***Not*** a duplicate (controlling the output from grep (independent of the matching, etc.)): *[How can I use grep to show just filenames on Linux?](https://stackoverflow.com/questions/6637882/how-can-i-use-grep-to-show-just-filenames-on-linux)* – Peter Mortensen Apr 24 '21 at 10:38
  • This question is a duplicate of [How can I recursively find all files in current and subfolders based on wildcard matching?](https://stackoverflow.com/q/5905054/11725753) – EvgenKo423 Jul 06 '21 at 17:43
  • @PeterMortensen the irony is by closing this and commenting you successfully put this into the first page of google results for this kind of question. – IT Alex Aug 08 '22 at 12:03

10 Answers10

158

You need to use find instead of grep in this case.

You can also use find in combination with grep or egrep:

$ find | grep "f[[:alnum:]]\.frm"
Pablo Santa Cruz
  • 176,835
  • 32
  • 241
  • 292
  • 24
    This is unnecessary. Find has that functionality built-in with the `-regex` option. – whereswalden Aug 11 '14 at 21:05
  • 9
    it is unnecessary here, but grep supports perl regex whereas find does not. – Dan Oct 28 '17 at 20:39
  • @alpha_989, I said grep supports it, which it does: https://www.gnu.org/software/grep/manual/html_node/grep-Programs.html#grep-Programs point is piping to grep is only needed if you need pcre. whereswalden has the right answer – Dan Mar 29 '18 at 19:19
  • 2
    @RM: No, that still searches file contents. It just *prints* file names instead of printing the matching lines. – user2357112 Mar 31 '21 at 22:45
122

Example

find <path> -name '*FileName*'

From manual:

find -name pattern

Base of file name (the path with the leading directories removed) matches shell pattern pattern. Because the leading directories are removed, the file names considered for a match with -name will never include a slash, so "-name a/b" will never match anything (you probably need to use -path instead). The metacharacters ("*", "?", and "[]") match a "." at the start of the base name (this is a change in find‐ utils-4.2.2; see section STANDARDS CONFORMANCE below). To ignore a directory and the files under it, use -prune; see an example in the description of -path. Braces are not recognised as being special, despite the fact that some shells including Bash imbue braces with a special meaning in shell patterns. The filename matching is performed with the use of the fnmatch(3) library function. Don't forget to enclose the pattern in quotes in order to protect it from expansion by the shell.

user2357112
  • 260,549
  • 28
  • 431
  • 505
javaPlease42
  • 4,699
  • 7
  • 36
  • 65
58

As Pablo said, you need to use find instead of grep, but there's no need to pipe find to grep. find has that functionality built in:

find . -regex 'f[[:alnum:]]\.frm'

find is a very powerful program for searching for files by name and supports searching by file type, depth limiting, combining different search terms with boolean operations, and executing arbitrary commands on found files. See the find man page for more information.

whereswalden
  • 4,819
  • 3
  • 27
  • 41
  • 1
    I would add the very handy feature of find to search by date with `-mtime` and `-mmin` – Johnride Nov 03 '14 at 20:38
  • 1
    Also, -regex switch performs matches with the whole path. So to work the example needs to add .* at the regex beginning. – tumasgiu Nov 29 '16 at 12:28
23

You can find the relative path of a file using tree. Just pipe the output to grep to filter down:

tree -f | grep filename

Here is a function you can put into your .bash_profile, .bashrc, .zshrc or other...

findfile(){ tree -f | grep $1; } # $1 = filename, -f is full path
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jasonleonhard
  • 12,047
  • 89
  • 66
22

The easiest way is

find . | grep test

Here find will list all the files in the (.), i.e., the current directory, recursively.

And then it is just a simple grep. All the files which name has "test" will appear.

You can play with grep as per your requirement. Note: As the grep is a generic string classification. It can result in giving you not only file names. But if a path has a directory ('/xyz_test_123/other.txt') it would also be part of the result set.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sachyy
  • 532
  • 4
  • 8
13
find -iname "file_name"

Syntax:
find -type type_descriptor file_name_here

type_descriptor types:

f: regular file

d: directory

l: symbolic link

c: character devices

b: block devices

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sireesh Yarlagadda
  • 12,978
  • 3
  • 74
  • 76
6
find . | grep KeywordToSearch

Here . means the current directory which is the value for the path parameter for the find command. It is piped to grep to search the keyword which should return all matching results.

Note: This is case sensitive. So for example fileName and FileName are not same.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
darth vader
  • 501
  • 8
  • 11
4

You can also do:

tree | grep filename

This pipes the output of the tree command to grep for a search. This will only tell you whether the file exists though.

caylus
  • 470
  • 4
  • 11
-1

Also for multiple files.

tree /path/to/directory/ | grep -i "file1 \| file2 \| file3"
DimiDak
  • 4,820
  • 2
  • 26
  • 32
-2

No, grep works just fine for this:

 grep -rl "filename" [starting point]

 grep -rL "not in filename"
R M
  • 542
  • 4
  • 11
  • 3
    This searches file contents for "filename", then prints the names of files with matches. OP wants match file names, not file contents. – Matthew Jun 25 '18 at 21:07
  • 3
    Agreed, this doesn't search filenames, it just prints the names of the filenames for which it's found *content* matches. You've misunderstood both the `-l` and `-L` options considerably. – Hashim Aziz Sep 16 '18 at 18:11