2

I have files named lect1.txt, lect2.doc, and lect3.doc.

I want to get a file which is a .txt file, and contains lect as the filename.

I tried

find *.txt | grep lect*

and it returned nothing.

but when I did

find *.txt | grep "lect*"

it returned lect1.txt.

What's the difference between these two expressions?

3
  • Use find . -name "*lect*.txt" ;)
    – A.B.
    Commented Mar 26, 2015 at 17:20
  • @A.B. I think I know that solution, but I'm curious about the apostrophe making changes to the result. Why is it necessary? I wrote those file names inside a single file, and used grep lect* filename, and it worked. Is it something with the standard output? Commented Mar 26, 2015 at 17:26
  • 2
    Yes, the quotes change the meaning. Outside the quotes, the * is interpreted by the shell. It's therefore expanded to: lect1.txt lect2.doc lect3.doc
    – Sobrique
    Commented Mar 26, 2015 at 17:31

3 Answers 3

6

grep searches for the first argument (the pattern) in the files passed on the command line or stdin if no files are passed.

Without the quote your shell will expand lect* to all the files in the directory that begin with lect. Your command will then be:

grep lect1.txt lect2.doc lect3.doc

which means search for the text lect1.txt in both .doc files. Unless one of the .doc file has the phrase lect1.txt within it, it will return nothing. To be more precise, it will look for lect1 followed by any character (the .) followed by txt, so it would also find lect1-txt and lect1xtxt etc)

In your second example, you've quoted "lect.*" so that the shell doesn't expand it and it is passed as is to grep. With only a pattern passed as an argument, grep will search the filenames passed in stdin for the pattern, which is what you are after I believe.

1

find *.txt | grep lect*

You generally want to give a path name as the first argument to find(1), rather than a file name. It certainly is not a file name pattern. The shell is expanding *.txt into the name of all *.txt files in the current directory before calling find, which isn't what you want here.

More useful variants of that command are

find . -name 'lect*' | grep 'txt$'

or

find . -name 'lect*txt'

Also, note that find(1) uses glob expressions in -name primaries, whereas grep(1) uses regular expressions. That's important here because * means something a bit different in the two systems.

BSD and GNU implementations of find have the nonstandard -regex primary, which lets you use regular expressions instead:

find . -regex '.*/lect.*txt'

Note that the pattern must match the whole path found by find, which is why we need the .*/ prefix, and it isn't necessary to pin the txt to the end with $ as with grep.

0
1

You're misusing find and it's working accidentally. You see - by running:

find *.txt 

What you're actually doing is invoking:

find lect1.txt

And you're accomplishing little more than echo. If however, you run find with a search criteria - so for example:

find . -name '*.txt'

Then it will traverse the current directory . and print any filename matching the specification in any subdirectory.

Care should be taken though, because the '*' as interpreted by find, the * in the shell and the * in a regular regular expression differ in meaning.

If you're greping * means 'zero or more instances of the preceding character.

So you're actually:

  • echoing all your filenames (globbing *.txt).
  • grepping to print any that match any characters with lec, lect, lectt, lecttttttt etc. in the middle.

In your first example though, you grep isn't even getting that far - the shell is expanding your pattern, so it's actually grepping for anything that matches echo lect* - that may work accidentally, because you have a file in your directory that expands appropriately, but it isn't doing what you intended.

I would suggest instead what you want is:

find . -name 'lect*.txt' -print
1
  • *.txt is unlikely to contain lect2.doc in its expansion ;-).
    – dhag
    Commented Mar 26, 2015 at 17:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .