On these days learning linux, I found something confued me:
$ cat abcd
line One
line Two
line Three
$ cat abcd | grep *
$ _ //nothing greped
$ cat abcd | grep ""
line One
line Two
line Three
$ cat abcd | grep "*"
$ _ //nothing grepedthe "_" is just the cursor, don't get mistake :)
who would explain this? Thanks
34 Answers
The glob * is expanded by the shell to an alphabetic list of all (non-dot) the files in the current directory. The arguments to grep are a search expression and a list of files. So grep * ends up using the first file name as the search expression. You are looking for the first file's name (as a regular expression) in the other files.
Grep searches standard input only if you do not supply any explicit file names. See:
echo moo | grep . /etc/issue
Handmade Linux for OS/X v 0.001Incidentally, * is not a valid regular expression. As you have discovered, an empty search expression matches all input lines. A regular expression which matches all non-empty input lines is .; in regex, the dot is a metacharacter which matches one character, any character except newline. The kleene star is a suffix operator which allows for zero or more repetitions of the previous regular expression, so you frequently see the regex .* for "anything at all", but in this context, it is redundant, as you are already matching nothing at all with the empty search string.
Finally, it is considered bad form to cat a single file. Instead of cat file | grep "" you save a process and perhaps some scorn by having grep read the file directly; grep "" file
The grep * is going to do "globbing" expansion against the files in the current directory.
I can't predict exactly what will happen, but the * will certainly match the abcd filename. So you might end up searching for "abcd" in the abcd file. Or you might end up searching for the name of the (lexographically) first file in the other files.
If the current directory was empty, you would end up searching for *. But that won't work either because the first command line argument is a regex, and "*" is not a valid regex.
To prevent the globbing, write this:
$ cat abcd | grep "*"... but that doesn't make sense for the reason given above.
To search for a literal "*" character:
$ cat abcd | grep "\\*" 2 Before grep sees a command line argument, that argument is parsed by the shell. For the shell, * is a wildcard for "all non-dot files in the current directory". Since the shell handles the argument first, your line gets turned into this:
cat abcd | grep abcd otherfile zfile(assuming that those three files reside in your current directory). This is what grep gets to see of its arguments, but it's not what you want.
Instead, you could put the pattern for grep in quotation marks, so that it is not processed by the shell:
cat abcd | grep "*"That's better, but still not what you want: grep uses regular expressions, not shell-style wildcarding. The asterisk, for grep, means "0..n repetitions of the previous character" - a character you did not specify. Close, but no cigar.
If you want an "any" pattern, you are looking for "0..n repetitions of an arbitrary character". The latter is represented by the period ('.') in regular expressions:
cat abcd | grep ".*"That is what you were looking for.
Edit: The other case is more easily explained. With grep "" you are looking for an empty string, which is present as a substring in any string.
Bash always parses * as a wildcard placeholders for file in the directory. In your command bash undertands it as
cat abcd | grep abcd file1 file2 ...so it only shows empty output as it doesn't what you are searching for
1