The first part of your two commands (cat FILENAME
) is always the same and just prints the specified file's content to the STDOUT stream. I will not explain it any further.
The point of our interest is the grep
part.
Syntax of grep
:
grep [OPTIONS] PATTERN [FILE...]
You can pass grep
some options to tweak its behaviour (e.g set the used RegEx flavour or control the output formatting), but those are not used in your case.
The next single argument must be the pattern to match, where a regular expression ("RegEx") or a fixed string (if grep
is called with the -F
option) is required. In your example, this is the install
or "\ install\ "
part. I will explain it in the next paragraph.
After that, you specify the source of the data to match. This can either be a file name, or nothing. In the second case, grep
will read from the STDIN stream (standard input: normally what you type with the keyboard), where you pipe (|
) the output from the previous command.
How to correctly pass the "PATTERN" argument?
The pattern parameter must be a single argument. That means, you can't just pass several words or anything containing spaces or shell special characters here, because spaces are treated as argument separators in Bash and probably every other shell as well, and shell special characters such as ;
will break the command.
But you have two options to include spaces into the pattern to match anyway:
Put the entire string to match in single ('...'
) or double ("..."
) quotes. This way, the shell parses the entire quotes-enclosed string as one argument and passes it on to grep
.
Escape every space in the pattern with a backslash (\
). That means, you write a backslash before every space which you don't want to be seen as argument separator by the shell. But note that if you want to have an actual backslash in the pattern, you must escape it as well, by writing another backslash before it.
If we now analyse the difference of your two grep
command examples, we see the difference in what they match:
cat /var/log/dpkg.log | grep "\ install\ "
This matches the pattern install
. (Note the leading and trailing space!)
Here we see both methods: double quotes around the entire pattern and backslash-escaping the spaces inside it. It's superfluous to be honest, one would have been enough. Although it doesn't hurt in this case, you should not do this and decide on one method. Usually I would recommend to use quotation marks, as it's easier to read.
cat /var/log/dpkg.log | grep install
This matches the pattern install
. (No surrounding spaces.)
Here the pattern only consists of the word install
, nothing else. No spaces.
Difference between your commands:
As I said, the first of your examples only matches the word install
when it is surrounded by spaces. It would not match if e.g. there's a full stop or any other character directly before or after it instead. It would also not match the word directly at the beginning or end of a line.
The second example does not care about any spaces before or after the word install
. It also matches at line beginnings and endings as well as if it is surrounded by any punctuation. It even matches if there is a word containing this letter sequence anywhere, e.g. "uninstall", "reinstall" or "installation" too!
Example with correct/useful backslash escaping:
As in the example you provided the backslashes are superfluous, here the same example without quotes, but with backslash escaping only instead:
cat /var/log/dpkg.log | grep \ install\
Or if you want to match the string "I like Ubuntu" in a file /home/you/path with spaces/textfile
without using quotes, you would do that like this:
grep I\ like\ Ubuntu /home/you/path\ with\ spaces/textfile
You see that you must escape spaces in path- or filenames as well - or quote them. The line above is equal to the line below:
grep "I like Ubuntu" "/home/you/path with spaces/textfile"
Best Answer
According to manpage of grep:
Example:
I have a folder test in which there is a file 1.txt. 2.txt is a symbolic link to 1.txt such that output of
ls -l test
looks like:The content of 1.txt is:
If I want to search for "file" string in files inside test folder and I run:
I'll encounter an error:
But if I do:
I get an output:
On the other hand if I run:
I get output:
Here, I haven't explicitly mentioned to scan all the files. So, when I used
R
flag, symbolic link (here 2.txt) was respected and output was generated. But when I usedr
flag, symbolic link was ignored simply because I didn't mention to scan 2.txt also.