Chan Kim
Chan Kim

Reputation: 5999

grep excluding file name pattern

I've read Use grep --exclude/--include syntax to not grep through certain files
but in my CentOS6.4, when I do

grep --exclude=*.cmd ckim * -r

I see lots of grepped lines from *.cmd files.
so it seems the exclude option is not working for me.
What is wrong?
of course I can do things like

grep ckim \`find . -name \*.c -print\`

but I want to know why the grep doesn't work.

Upvotes: 33

Views: 57392

Answers (6)

clarke
clarke

Reputation: 31

The shortest code for multiple files (note the DOT for files ending in '~') is:

grep -lr --exclude=*.{zip,bak,~} "Hello world!" world/* (wrong code)
grep -lr --exclude=*{zip,bak,~} "Hello world!" world/* (correct code)

ChatGPT can give you the wrong code for this specific case. The dot is not followed by '~', as in nycity.txt~

Upvotes: 1

Tiago Lopo
Tiago Lopo

Reputation: 7969

You can quote the pattern:

grep -r --exclude="*.cmd"  "ckim" ./

PS. ./ is the current directory

Upvotes: 57

John B
John B

Reputation: 3646

If you want to exclude certain files to grep from, you should use the -l option.

grep -l --exclude=*.cmd ckim * -r

Upvotes: 0

Sylvain Leroux
Sylvain Leroux

Reputation: 52060

I see lots of grepped lines from *.cmd files. So it seems the exclude option is not working for me.

There is a shell option called nullglob that controls the expansion of shell patterns when there is no matching file.


So, given the following environment:

sh$ touch f.cmd g.sh
sh$ mkdir sub
sh$ echo ckim > sub/h.cmd
sh$ echo ckim > sub/i.cmd

On my system (where nullglob is unset), the following command:

grep --exclude=*.cmd ckim * -r

Is expanded ("understood") by the shell as:

grep --exclude=*.cmd ckim f.cmd g.sh sub -r

That is, I will recursively (-r) search for the string skim starting with f.cmd, g.sh and sub but excluding any file matching the pattern '*.cmd'.

The result is:

# nullglob is unset
sh$ grep --exclude=*.cmd ckim * -r
sub/i.sh:ckim

BUT if in your environment the option nullglob is set, the same command expands to:

grep ckim f.cmd g.sh sub -r

Notice how the whole --exclude=... has disappeared. So the result is:

# nullglob is set
sh$ grep --exclude=*.cmd ckim * -r
sub/i.sh:ckim
sub/h.cmd:ckim

An now, for the explanation. When the shell encounters a glob pattern (i.e.: containing * or ? or a few more special characters), it expands it with the matching files. But if there is no matching files, it either let the pattern as it (if nullglob is not set) or replace it with "nothing" (if nullglob is set).

Here the pattern is --include=*.cmd (at whole since there is no space in there). In the unlikely event you have a file matching this pattern it would have been replaced. Otherwise it is either let "as it" or completely removed -- depending on nullglob.


You can easely display, set (-s) or unset (-u) the status of nullglob option of your current bash:

sh$ shopt nullglob
nullglob        on

sh$ shopt -u nullglob
sh$ shopt nullglob
nullglob        off

sh$ shopt -s nullglob
sh$ shopt nullglob
nullglob        on

Upvotes: 1

Ajay
Ajay

Reputation: 785

you could also do something like this

grep -rn ckim * | grep -v '\.cmd'

Upvotes: 1

Timofey Stolbov
Timofey Stolbov

Reputation: 4631

Use . as pathspec instead of *.

grep -r --exclude \*.cmd ckim .

Upvotes: 3

Related Questions