3

Following the advice under this question, I am able to recursively grep for a string string within contents of a given directory dir as follows

grep -r --exclude-dir='.*' string dir

However, when I apply this to the current directory, as

$ grep -r --exclude-dir='.*' string .
$ 

I get no results, since the --exclude-dir='.*' option omits the current directory as hidden since it matches '.*'.

A work-around is to change to the parent directory via cd .., then run the command on the appropriate child, then cd again back into that original working directory. There must be a single-command that I can use to do this without the work-around of changing directories.

What is a single command to grep contents of the current directory, omitting contents of hidden directories?

mherzl
  • 1,509

5 Answers5

4

If you’re using GNU grep 2.11 or later, -r will start from the current directory if no directory is specified:

grep -r --exclude-dir='.*' string
Stephen Kitt
  • 434,908
  • Good on including the version note. With BSD grep it produces: grep: warning: recursive search of stdin – Wildcard Jun 19 '17 at 21:56
2

Since bash won't have grep traverse hidden directories by default (i. e. without dotglob enabled:

$ tree -a
.
├── .test
│   ├── .file
│   └── file
├── file
└── test
    ├── .file
    └── file

2 directories, 5 files

$ grep -r foo *
file:foo
test/.file:foo
test/file:foo

Just exclude hidden files:

$ grep --exclude=".*" -r foo *
file:foo
test/file:foo
DopeGhoti
  • 76,081
  • I am curious as to the reasoning behind the uncommented downvote. – DopeGhoti Jun 19 '17 at 21:47
  • I didn't downvote, but it's not true that grep doesn't traverse hidden directories. What you're seeing with grep -r foo * is that the shell glob * doesn't expand to include hidden directories/files, unless dotglob has been set with shopt -s dotglob. Try with grep -r foo . and you'll see the hidden directories are traversed by grep. Or, try with shopt -s dotglob and then grep -r foo *. – Wildcard Jun 19 '17 at 21:55
  • Fair point; I have clarified this in my answer. – DopeGhoti Jun 19 '17 at 22:22
  • This will still search files in hidden directories contained within the command line arguments. It will sort of work. For most cases it might be okay, but it's like defining "pi" as "3.1416"; you better know the caveats. – Wildcard Jun 19 '17 at 22:25
2

In shell glob (also known as filename patterns), . has no special meaning, * means zero or more characters, and ? means any single character.

What you want to exclude is a dot followed by at least one character, and then any number of characters. So use:

grep -r --exclude-dir='.?*' string .
Wildcard
  • 36,499
1

You could also specify the current directory using $(pwd) like:

grep -r --exclude-dir='.*' string "$(pwd)"
1

To recurse inside a single directory (not limiting sub-diredtories hidden files) use:

As echo dir/* will print all files inside dir, this will work for files inside some dir:

$ grep -r "string" $(echo dir/*)

just change dir to . (dot) and you will get exactly what you want:

$ grep -r "string" $(echo ./*)

If what is needed is no hidden files in any of the sub-directories, either use:

$ grep -r --exclude-dir='.*' "string"

Or use find:

find . -not -path '*/\.*' -type f -exec grep "string" {} \+