What is the difference between:
grep "string" . -r --include *.pl
and
grep "string" . -r --include "*.pl"
The latter includes files in subdirectoried while the former not. Why?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityThe *
(star, or asterisk) is a special character which is (usually) interpreted by the shell before it is given the command. It is (usually) expanded to all filenames except those with leading dots. See the bash manual about pattern matching for more information.
If placed in quotes the star will not be interpreted by the shell and is given to the command verbatim.
Examples explained. The quoted one:
grep "string" . -r --include "*.pl"
Here grep
will receive the option --include
with the argument *.pl
. That is a 4 character string starting with the character *
. What grep
does with that string is entirely up to grep
. In this case --include
means to only consider files matching the glob *.pl
.
AFAIK behind the scenes gnu grep uses the same pattern matching lib as gnu bash. That means it will include the same files as shown by echo *.pl
.
The not quoted one:
grep "string" . -r --include *.pl
Here the shell will first expand the glob *.pl
before executing the command. The glob will expand to all filenames ending in .pl
.
Suppose there are the files foo.pl
, bar.pl
and baz.pl
. After expanding the glob the command line looks like this:
grep "string" . -r --include foo.pl bar.pl baz.pl
Here grep
will receive the option --include
with the argument foo.pl
, followed by the options bar.pl
and baz.pl
.
--include foo.pl
instructs grep to only consider files matching the pattern foo.pl
. Since there are no wildcards (no stars) in the pattern the only file matching that will be the file named foo.pl
.
The options bar.pl
and baz.pl
instructs grep to also search in those files. But since they do not match the pattern foo.pl
they will be ignored as required by the previous --include
.
grep -r
seemed inconsistent but never noticed it was only when I used a *
.
The difference is that if you don't quote the pattern (*.pl
) it is expanded by the shell. For example, if you run your grep
in a directory that contains a file called foo.pl
, since the *pl
is expanded by the shell, what grep
actually sees is:
grep "string" . -r --include foo.pl
Since you tell it to only include foo.pl
it will only search through that one file.
If you quote your pattern, the shell will not expand it and grep
gets the correct command, namely
grep "string" . -r --include *pl
grep
; it's in the shell.grep
never sees the quotes.