- How to use grep on all files non-recursively in a directory?
- 6 Answers 6
- How to perform grep operation on all files in a directory?
- 5 Answers 5
- How to Perform Grep Search on All Files and in All Directories
- Grep search in all files of a directory
- Grep recursive search in all subdirectories of a directory
- Bonus tip: Exclude a certain directory from the recursive grep search
- To summarize
How to use grep on all files non-recursively in a directory?
Only the errors are printed, I don’t get the matching lines. I tried using the -s option, but to no avail.
- Why am I not being able to use grep on a directory, as in (1), when I should be able to? I’ve seen that done in plenty examples on the Internet.
Edit: When I say «using grep on a directory», I mean «search in all the files in that directory excluding its subdirectories». I believe that this is what grep does when you pass a directory to it in place of a file. Am I incorrect? - Please give me an explanation on the workings of grep that would explain the behavior of commands in (2).
Edit: Let me be more specific. Why does using wildcards to specify multiple files to search in for work with .bash* and not with * or even ./* ? - How can I search all the files in a directory (and not its subdirectories) using grep ?
Also you’re relying on the shell expanding wildcards such as * , known as globbing. Globbing does not include filenames starting with a dot such as .bashrc as standard. You can set shell options so that it will include these files, but you can get yourself in a bit of a mess if you don’t know what you’re doing. A good guide to understanding globing can be found here mywiki.wooledge.org/glob
I dunno why, but I’ve always done globbing on hidden files, and it has always worked. I haven’t change any setting or something. As I pointed out in (2), it works with grep «string» .bash* too.
Sorry, my last example was incorrect. You can search in hidden files as well, and suppressing the «is a directory» because Linux technically sees directories as a different type of file. The command would be then: grep «string» * .* 2>/dev/null or grep -s «string» * .*
6 Answers 6
In Bash, a glob will not expand into hidden files, so if you want to search all the files in a directory, you need to specify hidden files .* and non-hidden * .
To avoid the «Is a directory» errors, you could use -d skip , but on my system I also get an error grep: .gvfs: Permission denied † , so I suggest using -s , which hides all error messages.
So the command you are looking for is:
If you are searching files in another dir:
Another option is to use the dotglob shell option, which will make a glob include hidden files.
shopt -s dotglob grep -s "string" *
† Someone mentioned that I shouldn’t get this error. They may be right — I did some reading but couldn’t make heads or tails of it myself.
@Hashim Compare the output of echo * .* and echo *.* run in your home directory, and the difference should be obvious. Otherwise LMK and I’ll explain it.
Interesting, so echo * shows non-hidden files and folders, echo *.* shows non-hidden files, echo .* shows all files, and echo * .* shows all files and directories. But why the reason for the space between the two in the latter case? It feels messy to me. Is there not a way to combine the two to get the same results? Or otherwise is there a syntax explanation of why the two need to be separated here, or is * .* an exceptional case?
@Hashim I’m not sure how you came to those conclusions, so let me explain. First, directories are files in this context. In globs, * represents all non-hidden files (i.e. filenames which don’t start with a dot); .* represents all hidden files (i.e. filenames that do start with a dot); and *.* represents all non-hidden files which contain a dot. In echo * .* , the two globs must be separate because they are different globs: one for non-hidden, one for hidden. Though as I wrote in my answer, you can make * include hidden files by turning on the dotglob shell option.
Using *.* is common on Windows (DOS) as a way to list all files but on *nix will only include files with a dot in them, so it doesn’t make sense on *nix. Instead you use * to list all files except hidden files, and .* to list hidden files.
You need the -d skip option added on.
- Grep is searching inside of files. You can search recursively, as you said, if you want to search files inside of a directory.
- By default, grep will read all files, and it detects the directories. Because by default you have not defined what to do with the directories with the -d option, it give error output.
- Searching just within the parent directory would be grep -d skip «string» ./*
(a) Please see the edit. (b) Using -d skip does not work; it’s basically the same as -s ; also, see the edit. (c) Nope, grep -d skip «string» ./* does not work either.
Old timers would probably do this:
find . -type f -print0 | xargs -0 grep "string"
@wchargin: if you want the file name in the output when there’s only one file I think you want find . -type f -maxdepth 1 -exec grep string /dev/null <> +
Rephrasing — you want to grep the files in one level of subdirectory, but not recurse though all sub-sub directories?
Or if you don’t want the files in the current directory
Note this won’t find directories starting with a dot.
There’s also -maxdepth and -mindepth restriction parameters available to the find command too.
@Hashim nope mostly — cos */* only matches things with one slash. If you had a file named a/b in the current directory then `*/* would match that.
You can think like this, for example using grep.
So this search for string «PATH» listing name of the files below the user’s home directory, only for files that start with a dot .
/root/.bash_history /root/.bash_profile grep: /root/.cache: Is a directory grep: /root/.config: Is a directory grep: /root/.dbus: Is a directory
Using grep PATH ~/.[^.]* you’ll see all occurrence, including line with searching keyword.
/root/.bash_history:echo $PATH /root/.bash_history:echo $PATH /root/.bash_history:PATH=$PATH:~/bin /root/.bash_history:echo $PATH /root/.bash_profile:PATH=$PATH:$HOME/bin /root/.bash_profile:export PATH grep: /root/.cache: Is a directory grep: /root/.config: Is a directory grep: /root/.dbus: Is a directory
To get rid of error redirect to /dev/null for example
grep PATH ~/.[^.]* 2>/dev/null /root/.bash_history:echo $PATH /root/.bash_history:echo $PATH /root/.bash_history:PATH=$PATH:~/bin /root/.bash_history:echo $PATH /root/.bash_profile:PATH=$PATH:$HOME/bin /root/.bash_profile:export PATH
So you can apply this pattern for searching «Apache» string in files from /etc directory-looking only in files below this main directory. You see that this don’t return from /etc/httpd/conf/httpd.conf
grep Apache /etc/[^.]* 2>/dev/null /etc/passwd:apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin /etc/services:derby-repli 4851/tcp # Apache Derby Replication /etc/services:derby-repli 4851/udp # Apache Derby Replication
How to perform grep operation on all files in a directory?
Working with xenserver, and I want to perform a command on each file that is in a directory, grepping some stuff out of the output of the command and appending it in a file. I’m clear on the command I want to use and how to grep out string(s) as needed. But what I’m not clear on is how do I have it perform this command on each file, going to the next, until no more files are found.
5 Answers 5
In Linux, I normally use this command to recursively grep for a particular text within a directory:
- r = recursive i.e, search subdirectories within the current directory
- n = to print the line numbers to stdout
- i = case insensitive search
grep $PATTERN * would be sufficient. By default, grep would skip all subdirectories. However, if you want to grep through them, grep -r $PATTERN * is the case.
@Tomáš Zato, just supply all your file patterns instead of *: grep $PATTERN *.cpp *.h . If you need more specific rules for what files should be grepped, use find command (check Rob’s answer).
@Chris it’s possible you don’t have *.scss files in current directory but somewhere deeper in subdirs so grep does not look in all the files you wanted. You should use —include option to tell grep to look recursively for files that matches specific patterns: grep -r x —include ‘*.scss’ . (note the quotes, they prevent the pattern from being expanded by the shell). Or just use find (see Rob’s answer).
You want grep -s so you don’t get a warning for each subdirectory that grep skips. You should probably double-quote «$PATTERN» here.
How to Perform Grep Search on All Files and in All Directories
The versatile grep command lets you perform search for a text in all the files and all the subdirectories of a directory. Here’s how to do that.
Grep is an excellent tool when you have to search on the content of a file.
Usually, you run grep on a single file like this:
grep search_term filename
Grep is quite versatile. If you want to search all the files in a directory with grep, use it like this:
There is a problem with it. It only searches in all the files in the current directory. It won’t search in the subdirectories.
You can make grep search in all the files and all the subdirectories of the current directory using the -r recursive search option:
You may also specify the directory path if you are not in the directory where you want to perform the search:
grep -r search_term directory_path
That was a quick recap. Let me show you all this in details with proper examples so that it is easier for you to understand.
Grep search in all files of a directory
Here’s the directory structure I am going to use in this example. Except empty.txt, all files contain the term ‘simple’ on which I’ll perform the grep search.
[email protected]:~/scripts$ tree . ├── dir1 │ └── new_script.sh ├── dir2 │ └── your_script.sh ├── dir3 │ ├── empty.txt │ └── linked.txt -> ../../sample.txt ├── my_script.sh └── your_script.sh 3 directories, 6 files
To search for the word ‘simple’ in all the files of the current directories, just use wild card (*). The wild card actually substitutes with the name of all the files and directories in the current directory.
This will search in all the files in the current directories, but it won’t enter the subdirectories. Since you cannot directly grep search on a directory, it will show «XYZ is a directory» error along with search results.
If you are not in the same directory where you want to perform, you can specify the directory path and end it with /*
grep search_term directory_path/*
Basically, you are using the wild card to expand on all the elements (files and directories) of the given directory.
Now that you know that, let’s see how you can perform a recursive search with grep so that it also looks into the files in the subdirectories.
Grep recursive search in all subdirectories of a directory
Grep provides a -r option for the recursive search. With this option, grep will look into all the files in the current (or specified) directory and it will also look into all the files of all the subdirectories.
Here’s the recursive search I performed in the previous example to do a grep search in the current folder:
There is also a -R option for recursive search and it works almost the same as the -r option.
So, what’s the difference grep -r and grep -R ? Only one, actually. The -R is dereferenced search which means it will follow the symbolic links to go to the original file (which may be located in some other part of the system).
Take a look at the output of the -R search in the same example:
Did you notice that it gives an additional search result with the linked.txt which is basically a symbolic link and was omitted from the grep search with -r option?
If you are not in the directory where you want to perform the recursive search, just provide the absolute or relative path of the directory to grep command:
grep -r search_term path_to_directory
Bonus tip: Exclude a certain directory from the recursive grep search
Everything seems good but what if you want to exclude a certain directory from the recursive search? There is a provision for that too. I told you, grep is an extremely versatile command.
grep -r --exclude-dir=dir_name serach_term directory_path
That’s not it. You can exclude more than one subdirectory from the recursive search in the following fashion:
grep -r --exclude-dir= serach_term directory_path
Here’s what excluding directories look like in our example here:
And yes, as demonstrated by the example above, the exclusion works with both -r and -R recursive options.
To summarize
Here’s a quick summary of using grep search for multiple files and directories:
Grep Command | Description |
---|---|
grep string * | Searches in all the files in current directory |
grep string dir | Searches in all the files in dir directory |
grep -r string . | Recursive search in all the files in all the subdirectories |
grep -r string dir | Recursive search in all files in all the subdirectories of dir |
grep -R string . | Same as r but follows the symbolic links |
I hope you like this quick grep tip. If you want more, you may read this detailed tutorial on using the grep command:
Let me know if you have any questions or suggestions on this topic.