Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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 greped

the "_" is just the cursor, don't get mistake :)

who would explain this? Thanks

share|improve this question

migrated from stackoverflow.com May 2 '13 at 10:33

This question came from our site for professional and enthusiast programmers.

    
What is _? On my machine, it yields, _: command not found. –  ΔRob May 1 '13 at 19:58
    
Also, what precisely did you hope cat abcd | grep * would print? –  ΔRob May 1 '13 at 19:59
    
it's the cursor, just not blink here :) –  user2339055 May 2 '13 at 3:55

4 Answers 4

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.001

Incidentally, * 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

share|improve this answer

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 "\\*"
share|improve this answer
    
The best way to find out what would happen would be to try echo * –  wildplasser May 1 '13 at 10:50
    
Yea ... but >>I<< can't do that. That's why it is hard for me to predict what will happen :-) –  Stephen C May 1 '13 at 10:52

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.

share|improve this answer
    
Except cat is useless and the regex is useless. partmaps.org/era/unix/award.html –  tripleee May 1 '13 at 11:08
    
@tripleee: I've seen this "award" tossed around with glee on sites like SO. I don't think it is appropriate. We're not talking about production code here; the cat in this example is a generic stand-in for "when I'm grepping some arbitrary standard input". An answer is easier to comprehend when it doesn't turn an abstract example into something else entirely just for the sake of showing off your leet skills of avoiding "unnecessary" uses of cat -- but sticks with the original code and shows the few twists that are actually related to the core of the question. –  DevSolar May 1 '13 at 15:24
    
I see it as misguided; an answer which fails to explain tangents and caveats is just less valuable than an answer which also tries to ensure that the basic approach is sound. It's not as bad as the "try chmod 0777 *" answers you sometimes see, but there is a commonality in the "just fix the symptoms" approach. –  tripleee May 1 '13 at 15:44
    
@triplee: I don't discuss three vs. four space indenting, or eqyptian vs. ANSI brackets either when answering, unless it's topical. There is a fine line between being verbosely helpful and being condescending. –  DevSolar May 1 '13 at 20:04
    
Great explanation! But there is still a question: Why&How $ cat abcd | grep "" works? I mean it's just an empty string, what make it("") diff from "*" -- while "*" match nothing? –  user2339055 May 2 '13 at 4:08

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

share|improve this answer
    
Not always. If the * is quoted, it won't. –  Stephen C May 2 '13 at 10:56

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.