1

So I am experimenting with the power of grep using this resources

The problem I am currently encountering is that it doesn't seem to work as I intended. so I have an demo.txt file that contains foo.txt, I use this code to search it: grep [a-z][a-z]o.txt demo.txt but it returns empty. zsh: no matches found: [a-z][a-z]o.txt I wonder if my understanding of the use of square bracket is wrong?

here is the picture:

enter image description here

2
  • 10
    Please don't post images of text. Instead, copy/paste the text into your question and use the formatting tools to format it as code.
    – terdon
    Commented Jan 22, 2021 at 12:20
  • 2
    setopt NO_NO_MATCH in your .zshrc. This is one of the most annoying defaults in zsh, for someone coming from bash.
    – user339730
    Commented Jan 23, 2021 at 5:06

1 Answer 1

12

Because you aren't quoting the regular expression you want to pass to grep, it is being captured by the shell and the shell tries to expand it before calling grep. Now, the regular expression you have used happens to also be a valid shell glob pattern1 which means "list all files or directories in the current folder whose name is any two characters, followed by the string o.txt". If your current directory contains any files or subdirectories matching that glob, then the glob will be expanded to the matching file names:

$ ls
abo.txt  demo.txt

$ cat demo.txt
foo.txt

$ set -x
$ grep [a-z][a-z]o.txt demo.txt 
+zsh:7> grep abo.txt demo.txt

The set -x tells zsh to show the actual commands it runs. As you can see, [a-z][a-z]o.txt is expanded to the matching file name: abo.txt, and that is what is passed to grep.

Now, you didn't actually have any matching file names in your directory, which means that zsh expanded the pattern to an empty string and didn't even launch grep at all. That's why the error is zsh: no matches found: [a-z][a-z]o.txt. That is zsh telling you that it failed to expand the glob to any matching files.

And, finally, this is what happens if you quote the pattern properly:

$ grep '[a-z][a-z]o.txt' demo.txt 
+zsh:12> grep '[a-z][a-z]o.txt' demo.txt
foo.txt

This time, the quotes protected the pattern from the shell, which passed it as is to grep and grep in turn interpreted it as a regular expression meaning "any two lower case letters, then an o, then any other character, and ending with txt". This is an important detail since . in a regular expression means "any character". So what you really wanted, was:

grep '[a-z][a-z]o\.txt' demo.txt 

The \. "escapes" the . so that it only matches a literal dot and no longer means "any character". So, always quote your regular expressions and be careful with .!

Finally, here's an alternative way of writing this using extended regular expressions:

$ grep -E '[a-z]{2}o\.txt' demo.txt      
foo.txt

1See What is the definition of a regular expression? for some more detail on globs vs regular expressions.

0

You must log in to answer this question.

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