32

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.

Community
  • 1
  • 1
Chan Kim
  • 5,177
  • 12
  • 57
  • 112

6 Answers6

55

You can quote the pattern:

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

PS. ./ is the current directory

Chan Kim
  • 5,177
  • 12
  • 57
  • 112
Tiago Lopo
  • 7,619
  • 1
  • 30
  • 51
  • 1
    This won't give a significant difference unless the OP has set `nullglob`. `--exclude=*.cmd` is unlikely to match a single file and would remain as is as an argument. It's the right practice but it doesn't give the solution. – konsolebox Jul 19 '14 at 09:52
  • @konsolebox, I must admit I don't know much about `nullglob` but `shopt` says it's `off` and still works. Am I missing something? – Tiago Lopo Jul 19 '14 at 11:11
  • It should work but even if unquoted it still would. I might be wrong with my assumption actually, and that your code may actually be able to help solve the issue - not because you're helping it prevent itself from expanding to a file, but because you help prevent it from becoming nullified when `nullglob` is enabled. Thanks to quoting, any kind of pathname expansion is prevented. I can't believe I really overlooked that part. – konsolebox Jul 19 '14 at 11:29
3

Use . as pathspec instead of *.

grep -r --exclude \*.cmd ckim .
Timofey Stolbov
  • 4,501
  • 3
  • 40
  • 45
1

you could also do something like this

grep -rn ckim * | grep -v '\.cmd'
Ajay
  • 775
  • 5
  • 19
  • 1
    This has unwanted behaviour, imagine the line inside the file has `something.cmd` it will not display that line even if the filename does not contain `\.cmd` – Tiago Lopo Jul 19 '14 at 09:30
  • Yes it has some unwanted behavior ... but there will be very much less possibility of ckim occurring with '.cmd' on the same line – Ajay Jul 19 '14 at 12:43
1

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
Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
1

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~

clarke
  • 21
  • 2
0

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

grep -l --exclude=*.cmd ckim * -r
John B
  • 3,566
  • 1
  • 16
  • 20